diff --git a/Gopkg.lock b/Gopkg.lock index cd5043e145a45557d1b0e1bac07f1b9157de0af0..915582b329cf003fe55eee006d9b3ff9f033b422 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -655,16 +655,18 @@ revision = "02b4e95473316948020af0b7a4f0f22c73929b0e" [[projects]] - digest = "1:5f31b45ee9da7a87f140bef3ed0a7ca34ea2a6d38eb888123b8e28170e8aa4f2" + digest = "1:d141efe4aaad714e3059c340901aab3147b6253e58c85dafbcca3dd8b0e88ad6" name = "google.golang.org/grpc" packages = [ ".", "balancer", "balancer/base", "balancer/roundrobin", + "binarylog/grpc_binarylog_v1", "codes", "connectivity", "credentials", + "credentials/internal", "credentials/oauth", "encoding", "encoding/gzip", @@ -672,8 +674,13 @@ "grpclog", "internal", "internal/backoff", + "internal/binarylog", "internal/channelz", + "internal/envconfig", "internal/grpcrand", + "internal/grpcsync", + "internal/syscall", + "internal/transport", "keepalive", "metadata", "naming", @@ -684,11 +691,10 @@ "stats", "status", "tap", - "transport", ] pruneopts = "" - revision = "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" - version = "v1.13.0" + revision = "df014850f6dee74ba2fc94874043a9f3f75fbfd8" + version = "v1.17.0" [[projects]] digest = "1:1c59d1f588f06f61d72480163b90a67f9380aca3d6c8ed6fee27d29a8d0ea515" diff --git a/Gopkg.toml b/Gopkg.toml index 5dbc48fcd4310daf5b7e3a480989c98582cc4d74..e16a8bfe0060e4caf3503a2b0e03bdad3ad286dc 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -8,7 +8,7 @@ [[constraint]] name = "google.golang.org/grpc" - version = "~1.13.0" + version = "~1.17.0" [[constraint]] name = "github.com/go-yaml/yaml" diff --git a/vendor/google.golang.org/grpc/.github/lock.yml b/vendor/google.golang.org/grpc/.github/lock.yml new file mode 100644 index 0000000000000000000000000000000000000000..78f7b19b71d337e4381413b2137391cdd890cebb --- /dev/null +++ b/vendor/google.golang.org/grpc/.github/lock.yml @@ -0,0 +1,2 @@ +daysUntilLock: 180 +lockComment: false diff --git a/vendor/google.golang.org/grpc/.travis.yml b/vendor/google.golang.org/grpc/.travis.yml index 3c2621ab750a4562acffad48dd5a32c889057150..f443eec9a0b45a1592a47d442ee4ae7577874ce6 100644 --- a/vendor/google.golang.org/grpc/.travis.yml +++ b/vendor/google.golang.org/grpc/.travis.yml @@ -1,24 +1,37 @@ language: go -go: - - 1.6.x - - 1.7.x - - 1.8.x - - 1.9.x - - 1.10.x - matrix: include: - - go: 1.10.x + - go: 1.11.x + env: VET=1 GO111MODULE=on + - go: 1.11.x + env: RACE=1 GO111MODULE=on + - go: 1.11.x env: RUN386=1 + - go: 1.11.x + env: GRPC_GO_RETRY=on + - go: 1.10.x + - go: 1.9.x + - go: 1.9.x + env: GAE=1 go_import_path: google.golang.org/grpc before_install: - - if [[ -n "$RUN386" ]]; then export GOARCH=386; fi - - if [[ "$TRAVIS_GO_VERSION" = 1.10* && "$GOARCH" != "386" ]]; then ./vet.sh -install || exit 1; fi + - if [[ "${GO111MODULE}" = "on" ]]; then mkdir "${HOME}/go"; export GOPATH="${HOME}/go"; fi + - if [[ -n "${RUN386}" ]]; then export GOARCH=386; fi + - if [[ "${TRAVIS_EVENT_TYPE}" = "cron" && -z "${RUN386}" ]]; then RACE=1; fi + - if [[ "${TRAVIS_EVENT_TYPE}" != "cron" ]]; then VET_SKIP_PROTO=1; fi + +install: + - try3() { eval "$*" || eval "$*" || eval "$*"; } + - try3 'if [[ "${GO111MODULE}" = "on" ]]; then go mod download; else make testdeps; fi' + - if [[ "${GAE}" = 1 ]]; then source ./install_gae.sh; make testappenginedeps; fi + - if [[ "${VET}" = 1 ]]; then ./vet.sh -install; fi script: - - if [[ "$TRAVIS_GO_VERSION" = 1.10* && "$GOARCH" != "386" ]]; then ./vet.sh || exit 1; fi - - make test || exit 1 - - if [[ "$GOARCH" != "386" ]]; then make testrace; fi + - set -e + - if [[ "${VET}" = 1 ]]; then ./vet.sh; fi + - if [[ "${GAE}" = 1 ]]; then make testappengine; exit 0; fi + - if [[ "${RACE}" = 1 ]]; then make testrace; exit 0; fi + - make test diff --git a/vendor/google.golang.org/grpc/Documentation/keepalive.md b/vendor/google.golang.org/grpc/Documentation/keepalive.md new file mode 100644 index 0000000000000000000000000000000000000000..118ac66d14d9e2e83fd8b3714de6fa09f7f7a9ec --- /dev/null +++ b/vendor/google.golang.org/grpc/Documentation/keepalive.md @@ -0,0 +1,46 @@ +# Keepalive + +gRPC sends http2 pings on the transport to detect if the connection is down. If +the ping is not acknowledged by the other side within a certain period, the +connection will be close. Note that pings are only necessary when there's no +activity on the connection. + +For how to configure keepalive, see +https://godoc.org/google.golang.org/grpc/keepalive for the options. + +## What should I set? + +It should be sufficient for most users to set [client +parameters](https://godoc.org/google.golang.org/grpc/keepalive) as a [dial +option](https://godoc.org/google.golang.org/grpc#WithKeepaliveParams). + +## What will happen? + +(The behavior described here is specific for gRPC-go, it might be slightly +different in other languages.) + +When there's no activity on a connection (note that an ongoing stream results in +__no activity__ when there's no message being sent), after `Time`, a ping will +be sent by the client and the server will send a ping ack when it gets the ping. +Client will wait for `Timeout`, and check if there's any activity on the +connection during this period (a ping ack is an activity). + +## What about server side? + +Server has similar `Time` and `Timeout` settings as client. Server can also +configure connection max-age. See [server +parameters](https://godoc.org/google.golang.org/grpc/keepalive#ServerParameters) +for details. + +### Enforcement policy + +[Enforcement +policy](https://godoc.org/google.golang.org/grpc/keepalive#ServerParameters) is +a special setting on server side to protect server from malicious or misbehaving +clients. + +Server sends GOAWAY with ENHANCE_YOUR_CALM and close the connection when bad +behaviors are detected: + - Client sends too frequent pings + - Client sends pings when there's no stream and this is disallowed by server + config diff --git a/vendor/google.golang.org/grpc/Documentation/proxy.md b/vendor/google.golang.org/grpc/Documentation/proxy.md new file mode 100644 index 0000000000000000000000000000000000000000..8fd6ee5248a8867a455fa95810e7a4db9e856aec --- /dev/null +++ b/vendor/google.golang.org/grpc/Documentation/proxy.md @@ -0,0 +1,15 @@ +# Proxy + +HTTP CONNECT proxies are supported by default in gRPC. The proxy address can be +specified by the environment variables HTTP_PROXY, HTTPS_PROXY and NO_PROXY (or +the lowercase versions thereof). + +## Custom proxy + +Currently, proxy support is implemented in the default dialer. It does one more +handshake (a CONNECT handshake in the case of HTTP CONNECT proxy) on the +connection before giving it to gRPC. + +If the default proxy doesn't work for you, replace the default dialer with your +custom proxy dialer. This can be done using +[`WithDialer`](https://godoc.org/google.golang.org/grpc#WithDialer). \ No newline at end of file diff --git a/vendor/google.golang.org/grpc/Documentation/server-reflection-tutorial.md b/vendor/google.golang.org/grpc/Documentation/server-reflection-tutorial.md index ca8e30cb41866de4f900fd111d6a909fb714d554..2e3d1c7719b6975a4996cf3587d8d43055e192a4 100644 --- a/vendor/google.golang.org/grpc/Documentation/server-reflection-tutorial.md +++ b/vendor/google.golang.org/grpc/Documentation/server-reflection-tutorial.md @@ -16,7 +16,6 @@ For example, to enable server reflection in `example/helloworld`, we need to mak --- a/examples/helloworld/greeter_server/main.go +++ b/examples/helloworld/greeter_server/main.go @@ -40,6 +40,7 @@ import ( - "golang.org/x/net/context" "google.golang.org/grpc" pb "google.golang.org/grpc/examples/helloworld/helloworld" + "google.golang.org/grpc/reflection" diff --git a/vendor/google.golang.org/grpc/Documentation/stickiness.md b/vendor/google.golang.org/grpc/Documentation/stickiness.md deleted file mode 100644 index e5db053a6b4b4ffe1bbc75b329975086ce02000a..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/Documentation/stickiness.md +++ /dev/null @@ -1,46 +0,0 @@ -# Stickiness - -With load balancer, each RPC pick a different backend based on the load -balancing policy. Stickiness policies try to preserve peers for the duration of -a session, so that RPCs with the same stickiness key will be directed to the -same server. - -Note that there's only "soft" stickiness now, which means RPCs with the same -stickienss key could still be sent to different servers. If stickiness is -critical for the system, server side application level handling is still -necessary. - -## Stickiness Key - -A stickiness key works as the session id. RPCs with the same stickiness key will -be assigned to the same backend. - -Stickiness key is set as part of the custom metadata. - -## Enable stickiness - -Stickiness can be enabled by setting `stickinessKey` field in [service -config](https://github.com/grpc/grpc/blob/master/doc/service_config.md). - -```json -{ - "stickinessKey": "sessionid" -} -``` - -The value `sesseionid` will be used as the key of the metadata entry that -defines the stickiness key for each RPC. - -## Send RPC with stickiness - -To set the stickiness key for an RPC, set the corresponding metadata. The -following RPC will be sent with stickiness key `session1`. - -```go -// "sessionid" is the metadata key specified by service config, "session1" is -// the stickiness key for this RPC. -md := metadata.Paris("sessionid", "session1") - -ctx := metadata.NewOutgoingContext(context.Background(), md) -resp, err := client.SomeRPC(ctx, req) -``` diff --git a/vendor/google.golang.org/grpc/Makefile b/vendor/google.golang.org/grpc/Makefile index 6f393a808dfaf9b645a4289fcdc2bebd5e4453b1..41a754f977283b6e420d86e7fb8ab59c1519cfb2 100644 --- a/vendor/google.golang.org/grpc/Makefile +++ b/vendor/google.golang.org/grpc/Makefile @@ -1,20 +1,14 @@ -all: vet test testrace - -deps: - go get -d -v google.golang.org/grpc/... - -updatedeps: - go get -d -v -u -f google.golang.org/grpc/... - -testdeps: - go get -d -v -t google.golang.org/grpc/... - -updatetestdeps: - go get -d -v -t -u -f google.golang.org/grpc/... +all: vet test testrace testappengine build: deps go build google.golang.org/grpc/... +clean: + go clean -i google.golang.org/grpc/... + +deps: + go get -d -v google.golang.org/grpc/... + proto: @ if ! which protoc > /dev/null; then \ echo "error: protoc not installed" >&2; \ @@ -22,27 +16,45 @@ proto: fi go generate google.golang.org/grpc/... -vet: - ./vet.sh - test: testdeps - go test -cpu 1,4 -timeout 5m google.golang.org/grpc/... + go test -cpu 1,4 -timeout 7m google.golang.org/grpc/... + +testappengine: testappenginedeps + goapp test -cpu 1,4 -timeout 7m google.golang.org/grpc/... + +testappenginedeps: + goapp get -d -v -t -tags 'appengine appenginevm' google.golang.org/grpc/... + +testdeps: + go get -d -v -t google.golang.org/grpc/... testrace: testdeps go test -race -cpu 1,4 -timeout 7m google.golang.org/grpc/... -clean: - go clean -i google.golang.org/grpc/... +updatedeps: + go get -d -v -u -f google.golang.org/grpc/... + +updatetestdeps: + go get -d -v -t -u -f google.golang.org/grpc/... + +vet: vetdeps + ./vet.sh + +vetdeps: + ./vet.sh -install .PHONY: \ all \ - deps \ - updatedeps \ - testdeps \ - updatetestdeps \ build \ + clean \ + deps \ proto \ - vet \ test \ + testappengine \ + testappenginedeps \ + testdeps \ testrace \ - clean + updatedeps \ + updatetestdeps \ + vet \ + vetdeps diff --git a/vendor/google.golang.org/grpc/README.md b/vendor/google.golang.org/grpc/README.md index 789adfd6536259875891fe4a8d666e709c929d7f..e3fb3c75ae3c4c09280f2b498a71d9767405692d 100644 --- a/vendor/google.golang.org/grpc/README.md +++ b/vendor/google.golang.org/grpc/README.md @@ -16,7 +16,7 @@ $ go get -u google.golang.org/grpc Prerequisites ------------- -This requires Go 1.6 or later. Go 1.7 will be required soon. +gRPC-Go requires Go 1.9 or later. Constraints ----------- @@ -43,3 +43,25 @@ Please update proto package, gRPC package and rebuild the proto files: - `go get -u github.com/golang/protobuf/{proto,protoc-gen-go}` - `go get -u google.golang.org/grpc` - `protoc --go_out=plugins=grpc:. *.proto` + +#### How to turn on logging + +The default logger is controlled by the environment variables. Turn everything +on by setting: + +``` +GRPC_GO_LOG_VERBOSITY_LEVEL=99 GRPC_GO_LOG_SEVERITY_LEVEL=info +``` + +#### The RPC failed with error `"code = Unavailable desc = transport is closing"` + +This error means the connection the RPC is using was closed, and there are many +possible reasons, including: + 1. mis-configured transport credentials, connection failed on handshaking + 1. bytes disrupted, possibly by a proxy in between + 1. server shutdown + +It can be tricky to debug this because the error happens on the client side but +the root cause of the connection being closed is on the server side. Turn on +logging on __both client and server__, and see if there are any transport +errors. diff --git a/vendor/google.golang.org/grpc/balancer.go b/vendor/google.golang.org/grpc/balancer.go index e1730166cde61a5aefed53c1f76a72a7eccab4f5..a78e702baee3e06c4179f8cb399d774ff489a194 100644 --- a/vendor/google.golang.org/grpc/balancer.go +++ b/vendor/google.golang.org/grpc/balancer.go @@ -19,11 +19,10 @@ package grpc import ( - "fmt" + "context" "net" "sync" - "golang.org/x/net/context" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/grpclog" @@ -118,26 +117,6 @@ type Balancer interface { Close() error } -// downErr implements net.Error. It is constructed by gRPC internals and passed to the down -// call of Balancer. -type downErr struct { - timeout bool - temporary bool - desc string -} - -func (e downErr) Error() string { return e.desc } -func (e downErr) Timeout() bool { return e.timeout } -func (e downErr) Temporary() bool { return e.temporary } - -func downErrorf(timeout, temporary bool, format string, a ...interface{}) downErr { - return downErr{ - timeout: timeout, - temporary: temporary, - desc: fmt.Sprintf(format, a...), - } -} - // RoundRobin returns a Balancer that selects addresses round-robin. It uses r to watch // the name resolution updates and updates the addresses available correspondingly. // @@ -410,7 +389,3 @@ func (rr *roundRobin) Close() error { type pickFirst struct { *roundRobin } - -func pickFirstBalancerV1(r naming.Resolver) Balancer { - return &pickFirst{&roundRobin{r: r}} -} diff --git a/vendor/google.golang.org/grpc/balancer/balancer.go b/vendor/google.golang.org/grpc/balancer/balancer.go index f9d83c2f39ff29d359b8895e63ee41e290c3879a..1bf46aafe6fb9e130b48b124a44a300616248bed 100644 --- a/vendor/google.golang.org/grpc/balancer/balancer.go +++ b/vendor/google.golang.org/grpc/balancer/balancer.go @@ -21,13 +21,14 @@ package balancer import ( + "context" "errors" "net" "strings" - "golang.org/x/net/context" "google.golang.org/grpc/connectivity" "google.golang.org/grpc/credentials" + "google.golang.org/grpc/metadata" "google.golang.org/grpc/resolver" ) @@ -88,7 +89,15 @@ type SubConn interface { } // NewSubConnOptions contains options to create new SubConn. -type NewSubConnOptions struct{} +type NewSubConnOptions struct { + // CredsBundle is the credentials bundle that will be used in the created + // SubConn. If it's nil, the original creds from grpc DialOptions will be + // used. + CredsBundle credentials.Bundle + // HealthCheckEnabled indicates whether health check service should be + // enabled on this SubConn + HealthCheckEnabled bool +} // ClientConn represents a gRPC ClientConn. // @@ -125,6 +134,8 @@ type BuildOptions struct { // use to dial to a remote load balancer server. The Balancer implementations // can ignore this if it does not need to talk to another party securely. DialCreds credentials.TransportCredentials + // CredsBundle is the credentials bundle that the Balancer can use. + CredsBundle credentials.Bundle // Dialer is the custom dialer the Balancer implementation can use to dial // to a remote load balancer server. The Balancer implementations // can ignore this if it doesn't need to talk to remote balancer. @@ -143,12 +154,21 @@ type Builder interface { } // PickOptions contains addition information for the Pick operation. -type PickOptions struct{} +type PickOptions struct { + // FullMethodName is the method name that NewClientStream() is called + // with. The canonical format is /service/Method. + FullMethodName string + // Header contains the metadata from the RPC's client header. The metadata + // should not be modified; make a copy first if needed. + Header metadata.MD +} // DoneInfo contains additional information for done. type DoneInfo struct { // Err is the rpc error the RPC finished with. It could be nil. Err error + // Trailer contains the metadata from the RPC's trailer, if present. + Trailer metadata.MD // BytesSent indicates if any bytes have been sent to the server. BytesSent bool // BytesReceived indicates if any byte has been received from the server. diff --git a/vendor/google.golang.org/grpc/balancer/base/balancer.go b/vendor/google.golang.org/grpc/balancer/base/balancer.go index 23d13511bb2f495aa12a4b5b5dc5b9a59927c609..5f55b274f440ff53f3c1cceddd6515fb24f45ffd 100644 --- a/vendor/google.golang.org/grpc/balancer/base/balancer.go +++ b/vendor/google.golang.org/grpc/balancer/base/balancer.go @@ -19,7 +19,8 @@ package base import ( - "golang.org/x/net/context" + "context" + "google.golang.org/grpc/balancer" "google.golang.org/grpc/connectivity" "google.golang.org/grpc/grpclog" @@ -29,6 +30,7 @@ import ( type baseBuilder struct { name string pickerBuilder PickerBuilder + config Config } func (bb *baseBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) balancer.Balancer { @@ -43,6 +45,7 @@ func (bb *baseBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) // ErrNoSubConnAvailable, because when state of a SubConn changes, we // may call UpdateBalancerState with this picker. picker: NewErrPicker(balancer.ErrNoSubConnAvailable), + config: bb.config, } } @@ -60,6 +63,7 @@ type baseBalancer struct { subConns map[resolver.Address]balancer.SubConn scStates map[balancer.SubConn]connectivity.State picker balancer.Picker + config Config } func (b *baseBalancer) HandleResolvedAddrs(addrs []resolver.Address, err error) { @@ -74,7 +78,7 @@ func (b *baseBalancer) HandleResolvedAddrs(addrs []resolver.Address, err error) addrsSet[a] = struct{}{} if _, ok := b.subConns[a]; !ok { // a is a new address (not existing in b.subConns). - sc, err := b.cc.NewSubConn([]resolver.Address{a}, balancer.NewSubConnOptions{}) + sc, err := b.cc.NewSubConn([]resolver.Address{a}, balancer.NewSubConnOptions{HealthCheckEnabled: b.config.HealthCheck}) if err != nil { grpclog.Warningf("base.baseBalancer: failed to create new SubConn: %v", err) continue diff --git a/vendor/google.golang.org/grpc/balancer/base/base.go b/vendor/google.golang.org/grpc/balancer/base/base.go index 012ace2f2f78e8b25f419b05b067d17dc0de3fd2..34b1f2994a7d69a85c9285fa1ed074915abfd134 100644 --- a/vendor/google.golang.org/grpc/balancer/base/base.go +++ b/vendor/google.golang.org/grpc/balancer/base/base.go @@ -45,8 +45,20 @@ type PickerBuilder interface { // NewBalancerBuilder returns a balancer builder. The balancers // built by this builder will use the picker builder to build pickers. func NewBalancerBuilder(name string, pb PickerBuilder) balancer.Builder { + return NewBalancerBuilderWithConfig(name, pb, Config{}) +} + +// Config contains the config info about the base balancer builder. +type Config struct { + // HealthCheck indicates whether health checking should be enabled for this specific balancer. + HealthCheck bool +} + +// NewBalancerBuilderWithConfig returns a base balancer builder configured by the provided config. +func NewBalancerBuilderWithConfig(name string, pb PickerBuilder, config Config) balancer.Builder { return &baseBuilder{ name: name, pickerBuilder: pb, + config: config, } } diff --git a/vendor/google.golang.org/grpc/balancer/grpclb/grpc_lb_v1/load_balancer.pb.go b/vendor/google.golang.org/grpc/balancer/grpclb/grpc_lb_v1/load_balancer.pb.go index d08bffc47a05f5741d5076c5c8fedef1bc09ce0d..78b1c537a86ac3b0c339a60b40c83ee78da75e6f 100644 --- a/vendor/google.golang.org/grpc/balancer/grpclb/grpc_lb_v1/load_balancer.pb.go +++ b/vendor/google.golang.org/grpc/balancer/grpclb/grpc_lb_v1/load_balancer.pb.go @@ -39,7 +39,7 @@ func (m *LoadBalanceRequest) Reset() { *m = LoadBalanceRequest{} } func (m *LoadBalanceRequest) String() string { return proto.CompactTextString(m) } func (*LoadBalanceRequest) ProtoMessage() {} func (*LoadBalanceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_load_balancer_077502ef49b0d1b1, []int{0} + return fileDescriptor_load_balancer_12026aec3f0251ba, []int{0} } func (m *LoadBalanceRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_LoadBalanceRequest.Unmarshal(m, b) @@ -66,12 +66,14 @@ type isLoadBalanceRequest_LoadBalanceRequestType interface { type LoadBalanceRequest_InitialRequest struct { InitialRequest *InitialLoadBalanceRequest `protobuf:"bytes,1,opt,name=initial_request,json=initialRequest,proto3,oneof"` } + type LoadBalanceRequest_ClientStats struct { ClientStats *ClientStats `protobuf:"bytes,2,opt,name=client_stats,json=clientStats,proto3,oneof"` } func (*LoadBalanceRequest_InitialRequest) isLoadBalanceRequest_LoadBalanceRequestType() {} -func (*LoadBalanceRequest_ClientStats) isLoadBalanceRequest_LoadBalanceRequestType() {} + +func (*LoadBalanceRequest_ClientStats) isLoadBalanceRequest_LoadBalanceRequestType() {} func (m *LoadBalanceRequest) GetLoadBalanceRequestType() isLoadBalanceRequest_LoadBalanceRequestType { if m != nil { @@ -169,8 +171,10 @@ func _LoadBalanceRequest_OneofSizer(msg proto.Message) (n int) { } type InitialLoadBalanceRequest struct { - // Name of load balanced service (IE, service.googleapis.com). Its + // The name of the load balanced service (e.g., service.googleapis.com). Its // length should be less than 256 bytes. + // The name might include a port number. How to handle the port number is up + // to the balancer. Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -181,7 +185,7 @@ func (m *InitialLoadBalanceRequest) Reset() { *m = InitialLoadBalanceReq func (m *InitialLoadBalanceRequest) String() string { return proto.CompactTextString(m) } func (*InitialLoadBalanceRequest) ProtoMessage() {} func (*InitialLoadBalanceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_load_balancer_077502ef49b0d1b1, []int{1} + return fileDescriptor_load_balancer_12026aec3f0251ba, []int{1} } func (m *InitialLoadBalanceRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InitialLoadBalanceRequest.Unmarshal(m, b) @@ -223,7 +227,7 @@ func (m *ClientStatsPerToken) Reset() { *m = ClientStatsPerToken{} } func (m *ClientStatsPerToken) String() string { return proto.CompactTextString(m) } func (*ClientStatsPerToken) ProtoMessage() {} func (*ClientStatsPerToken) Descriptor() ([]byte, []int) { - return fileDescriptor_load_balancer_077502ef49b0d1b1, []int{2} + return fileDescriptor_load_balancer_12026aec3f0251ba, []int{2} } func (m *ClientStatsPerToken) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ClientStatsPerToken.Unmarshal(m, b) @@ -282,7 +286,7 @@ func (m *ClientStats) Reset() { *m = ClientStats{} } func (m *ClientStats) String() string { return proto.CompactTextString(m) } func (*ClientStats) ProtoMessage() {} func (*ClientStats) Descriptor() ([]byte, []int) { - return fileDescriptor_load_balancer_077502ef49b0d1b1, []int{3} + return fileDescriptor_load_balancer_12026aec3f0251ba, []int{3} } func (m *ClientStats) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ClientStats.Unmarshal(m, b) @@ -358,7 +362,7 @@ func (m *LoadBalanceResponse) Reset() { *m = LoadBalanceResponse{} } func (m *LoadBalanceResponse) String() string { return proto.CompactTextString(m) } func (*LoadBalanceResponse) ProtoMessage() {} func (*LoadBalanceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_load_balancer_077502ef49b0d1b1, []int{4} + return fileDescriptor_load_balancer_12026aec3f0251ba, []int{4} } func (m *LoadBalanceResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_LoadBalanceResponse.Unmarshal(m, b) @@ -385,12 +389,14 @@ type isLoadBalanceResponse_LoadBalanceResponseType interface { type LoadBalanceResponse_InitialResponse struct { InitialResponse *InitialLoadBalanceResponse `protobuf:"bytes,1,opt,name=initial_response,json=initialResponse,proto3,oneof"` } + type LoadBalanceResponse_ServerList struct { ServerList *ServerList `protobuf:"bytes,2,opt,name=server_list,json=serverList,proto3,oneof"` } func (*LoadBalanceResponse_InitialResponse) isLoadBalanceResponse_LoadBalanceResponseType() {} -func (*LoadBalanceResponse_ServerList) isLoadBalanceResponse_LoadBalanceResponseType() {} + +func (*LoadBalanceResponse_ServerList) isLoadBalanceResponse_LoadBalanceResponseType() {} func (m *LoadBalanceResponse) GetLoadBalanceResponseType() isLoadBalanceResponse_LoadBalanceResponseType { if m != nil { @@ -507,7 +513,7 @@ func (m *InitialLoadBalanceResponse) Reset() { *m = InitialLoadBalanceRe func (m *InitialLoadBalanceResponse) String() string { return proto.CompactTextString(m) } func (*InitialLoadBalanceResponse) ProtoMessage() {} func (*InitialLoadBalanceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_load_balancer_077502ef49b0d1b1, []int{5} + return fileDescriptor_load_balancer_12026aec3f0251ba, []int{5} } func (m *InitialLoadBalanceResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InitialLoadBalanceResponse.Unmarshal(m, b) @@ -556,7 +562,7 @@ func (m *ServerList) Reset() { *m = ServerList{} } func (m *ServerList) String() string { return proto.CompactTextString(m) } func (*ServerList) ProtoMessage() {} func (*ServerList) Descriptor() ([]byte, []int) { - return fileDescriptor_load_balancer_077502ef49b0d1b1, []int{6} + return fileDescriptor_load_balancer_12026aec3f0251ba, []int{6} } func (m *ServerList) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ServerList.Unmarshal(m, b) @@ -591,11 +597,13 @@ type Server struct { IpAddress []byte `protobuf:"bytes,1,opt,name=ip_address,json=ipAddress,proto3" json:"ip_address,omitempty"` // A resolved port number for the server. Port int32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"` - // An opaque but printable token given to the frontend for each pick. All - // frontend requests for that pick must include the token in its initial - // metadata. The token is used by the backend to verify the request and to - // allow the backend to report load to the gRPC LB system. The token is also - // used in client stats for reporting dropped calls. + // An opaque but printable token for load reporting. The client must include + // the token of the picked server into the initial metadata when it starts a + // call to that server. The token is used by the server to verify the request + // and to allow the server to report load to the gRPC LB system. The token is + // also used in client stats for reporting dropped calls. + // + // Its length can be variable but must be less than 50 bytes. LoadBalanceToken string `protobuf:"bytes,3,opt,name=load_balance_token,json=loadBalanceToken,proto3" json:"load_balance_token,omitempty"` // Indicates whether this particular request should be dropped by the client. // If the request is dropped, there will be a corresponding entry in @@ -610,7 +618,7 @@ func (m *Server) Reset() { *m = Server{} } func (m *Server) String() string { return proto.CompactTextString(m) } func (*Server) ProtoMessage() {} func (*Server) Descriptor() ([]byte, []int) { - return fileDescriptor_load_balancer_077502ef49b0d1b1, []int{7} + return fileDescriptor_load_balancer_12026aec3f0251ba, []int{7} } func (m *Server) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Server.Unmarshal(m, b) @@ -776,57 +784,56 @@ var _LoadBalancer_serviceDesc = grpc.ServiceDesc{ } func init() { - proto.RegisterFile("grpc/lb/v1/load_balancer.proto", fileDescriptor_load_balancer_077502ef49b0d1b1) + proto.RegisterFile("grpc/lb/v1/load_balancer.proto", fileDescriptor_load_balancer_12026aec3f0251ba) } -var fileDescriptor_load_balancer_077502ef49b0d1b1 = []byte{ - // 756 bytes of a gzipped FileDescriptorProto +var fileDescriptor_load_balancer_12026aec3f0251ba = []byte{ + // 752 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x55, 0xdd, 0x6e, 0x23, 0x35, - 0x14, 0xee, 0x90, 0x69, 0x36, 0x39, 0xa9, 0xb6, 0x59, 0x2f, 0x2c, 0x93, 0xec, 0x6e, 0x5b, 0x22, - 0xb1, 0x8a, 0xd0, 0x32, 0x43, 0x0a, 0x17, 0x20, 0x71, 0x01, 0xd9, 0x6a, 0x95, 0x2d, 0xbd, 0x88, - 0x9c, 0x4a, 0x54, 0x95, 0x90, 0x99, 0xc9, 0xb8, 0xa9, 0x55, 0xc7, 0x1e, 0x3c, 0x4e, 0x2a, 0xae, - 0x79, 0x1f, 0xc4, 0x2b, 0x20, 0x5e, 0x0c, 0x8d, 0xed, 0x49, 0xa6, 0x49, 0xa3, 0xbd, 0x69, 0x3d, - 0xe7, 0x7c, 0xfe, 0xce, 0xef, 0xe7, 0xc0, 0xd1, 0x4c, 0x65, 0xd3, 0x88, 0x27, 0xd1, 0x72, 0x10, - 0x71, 0x19, 0xa7, 0x24, 0x89, 0x79, 0x2c, 0xa6, 0x54, 0x85, 0x99, 0x92, 0x5a, 0x22, 0x28, 0xfc, - 0x21, 0x4f, 0xc2, 0xe5, 0xa0, 0x7b, 0x34, 0x93, 0x72, 0xc6, 0x69, 0x64, 0x3c, 0xc9, 0xe2, 0x26, - 0x4a, 0x17, 0x2a, 0xd6, 0x4c, 0x0a, 0x8b, 0xed, 0x1e, 0x6f, 0xfa, 0x35, 0x9b, 0xd3, 0x5c, 0xc7, - 0xf3, 0xcc, 0x02, 0x7a, 0xff, 0x7a, 0x80, 0x2e, 0x64, 0x9c, 0x0e, 0x6d, 0x0c, 0x4c, 0xff, 0x58, - 0xd0, 0x5c, 0xa3, 0x31, 0x1c, 0x32, 0xc1, 0x34, 0x8b, 0x39, 0x51, 0xd6, 0x14, 0x78, 0x27, 0x5e, - 0xbf, 0x75, 0xfa, 0x65, 0xb8, 0x8e, 0x1e, 0x7e, 0xb0, 0x90, 0xed, 0xfb, 0xa3, 0x3d, 0xfc, 0xd4, - 0xdd, 0x2f, 0x19, 0x7f, 0x84, 0x83, 0x29, 0x67, 0x54, 0x68, 0x92, 0xeb, 0x58, 0xe7, 0xc1, 0x27, - 0x86, 0xee, 0xf3, 0x2a, 0xdd, 0x3b, 0xe3, 0x9f, 0x14, 0xee, 0xd1, 0x1e, 0x6e, 0x4d, 0xd7, 0x9f, - 0xc3, 0x97, 0xd0, 0xa9, 0xb6, 0xa2, 0x4c, 0x8a, 0xe8, 0x3f, 0x33, 0xda, 0x8b, 0xa0, 0xb3, 0x33, - 0x13, 0x84, 0xc0, 0x17, 0xf1, 0x9c, 0x9a, 0xf4, 0x9b, 0xd8, 0x9c, 0x7b, 0xbf, 0xc3, 0xf3, 0x4a, - 0xac, 0x31, 0x55, 0x97, 0xf2, 0x8e, 0x0a, 0xf4, 0x16, 0xd0, 0x83, 0x20, 0xba, 0xb0, 0xba, 0x8b, - 0x6d, 0xbe, 0xa6, 0xb6, 0xe8, 0x97, 0xd0, 0x14, 0x8b, 0x39, 0x99, 0xc6, 0x9c, 0xdb, 0x6a, 0x6a, - 0xb8, 0x21, 0x16, 0xf3, 0x77, 0xc5, 0x77, 0xef, 0x9f, 0x1a, 0xb4, 0x2a, 0x21, 0xd0, 0xf7, 0xd0, - 0x5c, 0x75, 0xde, 0x75, 0xb2, 0x1b, 0xda, 0xd9, 0x84, 0xe5, 0x6c, 0xc2, 0xcb, 0x12, 0x81, 0xd7, - 0x60, 0xf4, 0x15, 0x3c, 0x5b, 0x85, 0x29, 0x5a, 0xa7, 0x34, 0x4d, 0x5d, 0xb8, 0xc3, 0x32, 0xdc, - 0xc4, 0x9a, 0x8b, 0x02, 0xd6, 0xd8, 0x1b, 0x26, 0x58, 0x7e, 0x4b, 0xd3, 0xa0, 0x66, 0xc0, 0xed, - 0x12, 0xfc, 0xde, 0xd9, 0xd1, 0x6f, 0xf0, 0xf5, 0x36, 0x9a, 0xdc, 0x33, 0x7d, 0x4b, 0xdc, 0xa4, - 0x6e, 0x62, 0xc6, 0x69, 0x4a, 0xb4, 0x24, 0x39, 0x15, 0x69, 0x50, 0x37, 0x44, 0x6f, 0x36, 0x89, - 0x7e, 0x65, 0xfa, 0xd6, 0xd6, 0xfa, 0xde, 0xe0, 0x2f, 0xe5, 0x84, 0x8a, 0x14, 0x8d, 0xe0, 0x8b, - 0x47, 0xe8, 0xef, 0x84, 0xbc, 0x17, 0x44, 0xd1, 0x29, 0x65, 0x4b, 0x9a, 0x06, 0x4f, 0x0c, 0xe5, - 0xeb, 0x4d, 0xca, 0x5f, 0x0a, 0x14, 0x76, 0x20, 0x74, 0x05, 0xc1, 0x63, 0x49, 0xa6, 0x4a, 0x66, - 0x41, 0xe3, 0xa4, 0xd6, 0x6f, 0x9d, 0x1e, 0xef, 0x58, 0xa3, 0x72, 0xb4, 0xf8, 0xb3, 0xe9, 0x66, - 0xc6, 0x67, 0x4a, 0x66, 0xe7, 0x7e, 0xc3, 0x6f, 0xef, 0x9f, 0xfb, 0x8d, 0xfd, 0x76, 0xbd, 0xf7, - 0x9f, 0x07, 0xcf, 0x1f, 0xec, 0x4f, 0x9e, 0x49, 0x91, 0x53, 0x34, 0x81, 0xf6, 0x5a, 0x0a, 0xd6, - 0xe6, 0x26, 0xf8, 0xe6, 0x63, 0x5a, 0xb0, 0xe8, 0xd1, 0x1e, 0x3e, 0x5c, 0x89, 0xc1, 0x91, 0xfe, - 0x00, 0xad, 0x9c, 0xaa, 0x25, 0x55, 0x84, 0xb3, 0x5c, 0x3b, 0x31, 0xbc, 0xa8, 0xf2, 0x4d, 0x8c, - 0xfb, 0x82, 0x19, 0x31, 0x41, 0xbe, 0xfa, 0x1a, 0xbe, 0x82, 0xee, 0x86, 0x14, 0x2c, 0xa7, 0xd5, - 0xc2, 0xdf, 0x1e, 0x74, 0x77, 0xa7, 0x82, 0xbe, 0x83, 0x17, 0x0f, 0x9e, 0x14, 0x92, 0x52, 0x4e, - 0x67, 0xb1, 0x2e, 0xf5, 0xf1, 0x69, 0x65, 0xcd, 0xd5, 0x99, 0xf3, 0xa1, 0x6b, 0x78, 0x55, 0xd5, - 0x2e, 0x51, 0x34, 0x93, 0x4a, 0x13, 0x26, 0x34, 0x55, 0xcb, 0x98, 0xbb, 0xf4, 0x3b, 0x5b, 0x0b, - 0x7d, 0xe6, 0x1e, 0x23, 0xdc, 0xa9, 0x68, 0x19, 0x9b, 0xcb, 0x1f, 0xdc, 0xdd, 0xde, 0x4f, 0x00, - 0xeb, 0x52, 0xd1, 0x5b, 0x78, 0x62, 0x4b, 0xcd, 0x03, 0xcf, 0x4c, 0x16, 0x6d, 0xf7, 0x04, 0x97, - 0x90, 0x73, 0xbf, 0x51, 0x6b, 0xfb, 0xbd, 0xbf, 0x3c, 0xa8, 0x5b, 0x0f, 0x7a, 0x0d, 0xc0, 0x32, - 0x12, 0xa7, 0xa9, 0xa2, 0x79, 0x6e, 0x4a, 0x3a, 0xc0, 0x4d, 0x96, 0xfd, 0x6c, 0x0d, 0xc5, 0x5b, - 0x50, 0xc4, 0x36, 0xf9, 0xee, 0x63, 0x73, 0xde, 0x21, 0xfa, 0xda, 0x0e, 0xd1, 0x23, 0xf0, 0xcd, - 0xda, 0xf9, 0x27, 0x5e, 0xbf, 0x81, 0xcd, 0xd9, 0xae, 0xcf, 0x69, 0x02, 0x07, 0x95, 0x86, 0x2b, - 0x84, 0xa1, 0xe5, 0xce, 0x85, 0x19, 0x1d, 0x55, 0xeb, 0xd8, 0x7e, 0xa6, 0xba, 0xc7, 0x3b, 0xfd, - 0x76, 0x72, 0x7d, 0xef, 0x1b, 0x6f, 0x78, 0x05, 0x4f, 0x99, 0xb4, 0xc0, 0xe2, 0x0f, 0x4f, 0x86, - 0xcf, 0xaa, 0x31, 0xc7, 0x45, 0xdf, 0xc7, 0xde, 0xf5, 0xc0, 0xcd, 0x61, 0x26, 0x79, 0x2c, 0x66, - 0xa1, 0x54, 0xb3, 0xc8, 0xfc, 0xa4, 0x94, 0x43, 0x8f, 0xec, 0x65, 0xf3, 0x8f, 0xf0, 0x84, 0x2c, - 0x07, 0x49, 0xdd, 0xcc, 0xec, 0xdb, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x5f, 0xc0, 0x96, 0xfd, - 0x7c, 0x06, 0x00, 0x00, + 0x14, 0xee, 0x90, 0x69, 0x36, 0x39, 0x29, 0x34, 0xeb, 0x85, 0x65, 0x92, 0xdd, 0x6d, 0x4b, 0x24, + 0x56, 0x11, 0x2a, 0x13, 0x52, 0xb8, 0x00, 0x89, 0x0b, 0x48, 0xab, 0x2a, 0x2d, 0xbd, 0x88, 0x9c, + 0x4a, 0x45, 0x95, 0x90, 0x99, 0xc9, 0xb8, 0xa9, 0x55, 0xc7, 0x1e, 0x3c, 0x4e, 0x2a, 0xae, 0x79, + 0x1f, 0xc4, 0x2b, 0x20, 0x5e, 0x0c, 0x8d, 0xed, 0x49, 0xa6, 0x49, 0xa3, 0xbd, 0xca, 0xf8, 0x9c, + 0xcf, 0xdf, 0xf9, 0xfd, 0x1c, 0x38, 0x98, 0xaa, 0x74, 0xd2, 0xe3, 0x71, 0x6f, 0xd1, 0xef, 0x71, + 0x19, 0x25, 0x24, 0x8e, 0x78, 0x24, 0x26, 0x54, 0x85, 0xa9, 0x92, 0x5a, 0x22, 0xc8, 0xfd, 0x21, + 0x8f, 0xc3, 0x45, 0xbf, 0x7d, 0x30, 0x95, 0x72, 0xca, 0x69, 0xcf, 0x78, 0xe2, 0xf9, 0x5d, 0x2f, + 0x99, 0xab, 0x48, 0x33, 0x29, 0x2c, 0xb6, 0x7d, 0xb8, 0xee, 0xd7, 0x6c, 0x46, 0x33, 0x1d, 0xcd, + 0x52, 0x0b, 0xe8, 0xfc, 0xeb, 0x01, 0xba, 0x92, 0x51, 0x32, 0xb0, 0x31, 0x30, 0xfd, 0x63, 0x4e, + 0x33, 0x8d, 0x46, 0xb0, 0xcf, 0x04, 0xd3, 0x2c, 0xe2, 0x44, 0x59, 0x53, 0xe0, 0x1d, 0x79, 0xdd, + 0xc6, 0xc9, 0x97, 0xe1, 0x2a, 0x7a, 0x78, 0x61, 0x21, 0x9b, 0xf7, 0x87, 0x3b, 0xf8, 0x13, 0x77, + 0xbf, 0x60, 0xfc, 0x11, 0xf6, 0x26, 0x9c, 0x51, 0xa1, 0x49, 0xa6, 0x23, 0x9d, 0x05, 0x1f, 0x19, + 0xba, 0xcf, 0xcb, 0x74, 0xa7, 0xc6, 0x3f, 0xce, 0xdd, 0xc3, 0x1d, 0xdc, 0x98, 0xac, 0x8e, 0x83, + 0x37, 0xd0, 0x2a, 0xb7, 0xa2, 0x48, 0x8a, 0xe8, 0x3f, 0x53, 0xda, 0xe9, 0x41, 0x6b, 0x6b, 0x26, + 0x08, 0x81, 0x2f, 0xa2, 0x19, 0x35, 0xe9, 0xd7, 0xb1, 0xf9, 0xee, 0xfc, 0x0e, 0xaf, 0x4a, 0xb1, + 0x46, 0x54, 0x5d, 0xcb, 0x07, 0x2a, 0xd0, 0x31, 0xa0, 0x27, 0x41, 0x74, 0x6e, 0x75, 0x17, 0x9b, + 0x7c, 0x45, 0x6d, 0xd1, 0x6f, 0xa0, 0x2e, 0xe6, 0x33, 0x32, 0x89, 0x38, 0xb7, 0xd5, 0x54, 0x70, + 0x4d, 0xcc, 0x67, 0xa7, 0xf9, 0xb9, 0xf3, 0x4f, 0x05, 0x1a, 0xa5, 0x10, 0xe8, 0x7b, 0xa8, 0x2f, + 0x3b, 0xef, 0x3a, 0xd9, 0x0e, 0xed, 0x6c, 0xc2, 0x62, 0x36, 0xe1, 0x75, 0x81, 0xc0, 0x2b, 0x30, + 0xfa, 0x0a, 0x5e, 0x2e, 0xc3, 0xe4, 0xad, 0x53, 0x9a, 0x26, 0x2e, 0xdc, 0x7e, 0x11, 0x6e, 0x6c, + 0xcd, 0x79, 0x01, 0x2b, 0xec, 0x1d, 0x13, 0x2c, 0xbb, 0xa7, 0x49, 0x50, 0x31, 0xe0, 0x66, 0x01, + 0x3e, 0x77, 0x76, 0xf4, 0x1b, 0x7c, 0xbd, 0x89, 0x26, 0x8f, 0x4c, 0xdf, 0x13, 0x37, 0xa9, 0xbb, + 0x88, 0x71, 0x9a, 0x10, 0x2d, 0x49, 0x46, 0x45, 0x12, 0x54, 0x0d, 0xd1, 0xfb, 0x75, 0xa2, 0x1b, + 0xa6, 0xef, 0x6d, 0xad, 0xe7, 0x06, 0x7f, 0x2d, 0xc7, 0x54, 0x24, 0x68, 0x08, 0x5f, 0x3c, 0x43, + 0xff, 0x20, 0xe4, 0xa3, 0x20, 0x8a, 0x4e, 0x28, 0x5b, 0xd0, 0x24, 0x78, 0x61, 0x28, 0xdf, 0xad, + 0x53, 0xfe, 0x92, 0xa3, 0xb0, 0x03, 0xa1, 0x5f, 0x21, 0x78, 0x2e, 0xc9, 0x44, 0xc9, 0x34, 0xa8, + 0x1d, 0x55, 0xba, 0x8d, 0x93, 0xc3, 0x2d, 0x6b, 0x54, 0x8c, 0x16, 0x7f, 0x36, 0x59, 0xcf, 0xf8, + 0x4c, 0xc9, 0xf4, 0xd2, 0xaf, 0xf9, 0xcd, 0xdd, 0x4b, 0xbf, 0xb6, 0xdb, 0xac, 0x76, 0xfe, 0xf3, + 0xe0, 0xd5, 0x93, 0xfd, 0xc9, 0x52, 0x29, 0x32, 0x8a, 0xc6, 0xd0, 0x5c, 0x49, 0xc1, 0xda, 0xdc, + 0x04, 0xdf, 0x7f, 0x48, 0x0b, 0x16, 0x3d, 0xdc, 0xc1, 0xfb, 0x4b, 0x31, 0x38, 0xd2, 0x1f, 0xa0, + 0x91, 0x51, 0xb5, 0xa0, 0x8a, 0x70, 0x96, 0x69, 0x27, 0x86, 0xd7, 0x65, 0xbe, 0xb1, 0x71, 0x5f, + 0x31, 0x23, 0x26, 0xc8, 0x96, 0xa7, 0xc1, 0x5b, 0x68, 0xaf, 0x49, 0xc1, 0x72, 0x5a, 0x2d, 0xfc, + 0xed, 0x41, 0x7b, 0x7b, 0x2a, 0xe8, 0x3b, 0x78, 0xfd, 0xe4, 0x49, 0x21, 0x09, 0xe5, 0x74, 0x1a, + 0xe9, 0x42, 0x1f, 0x9f, 0x96, 0xd6, 0x5c, 0x9d, 0x39, 0x1f, 0xba, 0x85, 0xb7, 0x65, 0xed, 0x12, + 0x45, 0x53, 0xa9, 0x34, 0x61, 0x42, 0x53, 0xb5, 0x88, 0xb8, 0x4b, 0xbf, 0xb5, 0xb1, 0xd0, 0x67, + 0xee, 0x31, 0xc2, 0xad, 0x92, 0x96, 0xb1, 0xb9, 0x7c, 0xe1, 0xee, 0x76, 0x7e, 0x02, 0x58, 0x95, + 0x8a, 0x8e, 0xe1, 0x85, 0x2d, 0x35, 0x0b, 0x3c, 0x33, 0x59, 0xb4, 0xd9, 0x13, 0x5c, 0x40, 0x2e, + 0xfd, 0x5a, 0xa5, 0xe9, 0x77, 0xfe, 0xf2, 0xa0, 0x6a, 0x3d, 0xe8, 0x1d, 0x00, 0x4b, 0x49, 0x94, + 0x24, 0x8a, 0x66, 0x99, 0x29, 0x69, 0x0f, 0xd7, 0x59, 0xfa, 0xb3, 0x35, 0xe4, 0x6f, 0x41, 0x1e, + 0xdb, 0xe4, 0xbb, 0x8b, 0xcd, 0xf7, 0x16, 0xd1, 0x57, 0xb6, 0x88, 0x1e, 0x81, 0x6f, 0xd6, 0xce, + 0x3f, 0xf2, 0xba, 0x35, 0x6c, 0xbe, 0xed, 0xfa, 0x9c, 0xc4, 0xb0, 0x57, 0x6a, 0xb8, 0x42, 0x18, + 0x1a, 0xee, 0x3b, 0x37, 0xa3, 0x83, 0x72, 0x1d, 0x9b, 0xcf, 0x54, 0xfb, 0x70, 0xab, 0xdf, 0x4e, + 0xae, 0xeb, 0x7d, 0xe3, 0x0d, 0x6e, 0xe0, 0x63, 0x26, 0x4b, 0xc0, 0xc1, 0xcb, 0x72, 0xc8, 0x51, + 0xde, 0xf6, 0x91, 0x77, 0xdb, 0x77, 0x63, 0x98, 0x4a, 0x1e, 0x89, 0x69, 0x28, 0xd5, 0xb4, 0x67, + 0xfe, 0x51, 0x8a, 0x99, 0x9b, 0x13, 0x8f, 0xcd, 0x0f, 0xe1, 0x31, 0x59, 0xf4, 0xe3, 0xaa, 0x19, + 0xd9, 0xb7, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0x81, 0x14, 0xee, 0xd1, 0x7b, 0x06, 0x00, 0x00, } diff --git a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb.go b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb.go index 0c46ae32f8c968b0a7e644b9cfa0575f86aef649..789b9c4337d80f0a3b9763552e8b0cbebd993b8a 100644 --- a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb.go +++ b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb.go @@ -25,19 +25,21 @@ package grpclb import ( - "fmt" + "context" + "errors" "strconv" "strings" "sync" "time" durationpb "github.com/golang/protobuf/ptypes/duration" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/balancer" lbpb "google.golang.org/grpc/balancer/grpclb/grpc_lb_v1" "google.golang.org/grpc/connectivity" + "google.golang.org/grpc/credentials" "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/internal" "google.golang.org/grpc/internal/backoff" "google.golang.org/grpc/resolver" ) @@ -59,7 +61,7 @@ var ( defaultBackoffConfig = backoff.Exponential{ MaxDelay: 120 * time.Second, } - errServerTerminatedConnection = fmt.Errorf("grpclb: failed to recv server list: server terminated connection") + errServerTerminatedConnection = errors.New("grpclb: failed to recv server list: server terminated connection") ) func convertDuration(d *durationpb.Duration) time.Duration { @@ -166,13 +168,35 @@ func (b *lbBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) bal backoff: defaultBackoffConfig, // TODO: make backoff configurable. } + var err error + if opt.CredsBundle != nil { + lb.grpclbClientConnCreds, err = opt.CredsBundle.NewWithMode(internal.CredsBundleModeBalancer) + if err != nil { + grpclog.Warningf("lbBalancer: client connection creds NewWithMode failed: %v", err) + } + lb.grpclbBackendCreds, err = opt.CredsBundle.NewWithMode(internal.CredsBundleModeBackendFromBalancer) + if err != nil { + grpclog.Warningf("lbBalancer: backend creds NewWithMode failed: %v", err) + } + } + return lb } type lbBalancer struct { - cc *lbCacheClientConn - target string - opt balancer.BuildOptions + cc *lbCacheClientConn + target string + opt balancer.BuildOptions + + // grpclbClientConnCreds is the creds bundle to be used to connect to grpclb + // servers. If it's nil, use the TransportCredentials from BuildOptions + // instead. + grpclbClientConnCreds credentials.Bundle + // grpclbBackendCreds is the creds bundle to be used for addresses that are + // returned by grpclb server. If it's nil, don't set anything when creating + // SubConns. + grpclbBackendCreds credentials.Bundle + fallbackTimeout time.Duration doneCh chan struct{} @@ -302,7 +326,7 @@ func (lb *lbBalancer) fallbackToBackendsAfter(fallbackTimeout time.Duration) { return } lb.fallbackTimerExpired = true - lb.refreshSubConns(lb.resolvedBackendAddrs) + lb.refreshSubConns(lb.resolvedBackendAddrs, false) lb.mu.Unlock() } @@ -349,7 +373,7 @@ func (lb *lbBalancer) HandleResolvedAddrs(addrs []resolver.Address, err error) { // This means we received a new list of resolved backends, and we are // still in fallback mode. Need to update the list of backends we are // using to the new list of backends. - lb.refreshSubConns(lb.resolvedBackendAddrs) + lb.refreshSubConns(lb.resolvedBackendAddrs, false) } lb.mu.Unlock() } diff --git a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_picker.go b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_picker.go index d77af401b7c8c8a4b942561d1ea34364fd7d668a..026bbc7f4695c65a6d12286786ffab18db208b7b 100644 --- a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_picker.go +++ b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_picker.go @@ -19,10 +19,10 @@ package grpclb import ( + "context" "sync" "sync/atomic" - "golang.org/x/net/context" "google.golang.org/grpc/balancer" lbpb "google.golang.org/grpc/balancer/grpclb/grpc_lb_v1" "google.golang.org/grpc/codes" diff --git a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_remote_balancer.go b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_remote_balancer.go index d0ecd68be48d6dc5de3e0f8c30633f7f2ce6e642..7b35d111410c7d556511e8897d2c0dd50af4d0b8 100644 --- a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_remote_balancer.go +++ b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_remote_balancer.go @@ -19,6 +19,7 @@ package grpclb import ( + "context" "fmt" "io" "net" @@ -26,7 +27,6 @@ import ( "time" timestamppb "github.com/golang/protobuf/ptypes/timestamp" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/balancer" lbpb "google.golang.org/grpc/balancer/grpclb/grpc_lb_v1" @@ -80,7 +80,7 @@ func (lb *lbBalancer) processServerList(l *lbpb.ServerList) { } // Call refreshSubConns to create/remove SubConns. - lb.refreshSubConns(backendAddrs) + lb.refreshSubConns(backendAddrs, true) // Regenerate and update picker no matter if there's update on backends (if // any SubConn will be newed/removed). Because since the full serverList was // different, there might be updates in drops or pick weights(different @@ -96,7 +96,12 @@ func (lb *lbBalancer) processServerList(l *lbpb.ServerList) { // indicating whether the backendAddrs are different from the cached // backendAddrs (whether any SubConn was newed/removed). // Caller must hold lb.mu. -func (lb *lbBalancer) refreshSubConns(backendAddrs []resolver.Address) bool { +func (lb *lbBalancer) refreshSubConns(backendAddrs []resolver.Address, fromGRPCLBServer bool) bool { + opts := balancer.NewSubConnOptions{} + if fromGRPCLBServer { + opts.CredsBundle = lb.grpclbBackendCreds + } + lb.backendAddrs = nil var backendsUpdated bool // addrsSet is the set converted from backendAddrs, it's used to quick @@ -113,7 +118,7 @@ func (lb *lbBalancer) refreshSubConns(backendAddrs []resolver.Address) bool { backendsUpdated = true // Use addrWithMD to create the SubConn. - sc, err := lb.cc.NewSubConn([]resolver.Address{addr}, balancer.NewSubConnOptions{}) + sc, err := lb.cc.NewSubConn([]resolver.Address{addr}, opts) if err != nil { grpclog.Warningf("roundrobinBalancer: failed to create new SubConn: %v", err) continue @@ -236,7 +241,7 @@ func (lb *lbBalancer) watchRemoteBalancer() { if err == errServerTerminatedConnection { grpclog.Info(err) } else { - grpclog.Error(err) + grpclog.Warning(err) } } } @@ -266,6 +271,8 @@ func (lb *lbBalancer) dialRemoteLB(remoteLBName string) { grpclog.Warningf("grpclb: failed to override the server name in the credentials: %v, using Insecure", err) dopts = append(dopts, grpc.WithInsecure()) } + } else if bundle := lb.grpclbClientConnCreds; bundle != nil { + dopts = append(dopts, grpc.WithCredentialsBundle(bundle)) } else { dopts = append(dopts, grpc.WithInsecure()) } @@ -283,9 +290,12 @@ func (lb *lbBalancer) dialRemoteLB(remoteLBName string) { dopts = append(dopts, grpc.WithChannelzParentID(lb.opt.ChannelzParentID)) } - // DialContext using manualResolver.Scheme, which is a random scheme generated - // when init grpclb. The target name is not important. - cc, err := grpc.DialContext(context.Background(), "grpclb:///grpclb.server", dopts...) + // DialContext using manualResolver.Scheme, which is a random scheme + // generated when init grpclb. The target scheme here is not important. + // + // The grpc dial target will be used by the creds (ALTS) as the authority, + // so it has to be set to remoteLBName that comes from resolver. + cc, err := grpc.DialContext(context.Background(), remoteLBName, dopts...) if err != nil { grpclog.Fatalf("failed to dial: %v", err) } diff --git a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_test.go b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_test.go index 7e6ca76ed5efe2bbeb2e56c631c1eef456998771..7ad0f55686398c0418f86675a87707a2a5ddf7b4 100644 --- a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_test.go +++ b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_test.go @@ -19,6 +19,7 @@ package grpclb import ( + "context" "errors" "fmt" "io" @@ -31,7 +32,6 @@ import ( "time" durationpb "github.com/golang/protobuf/ptypes/duration" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/balancer" lbgrpc "google.golang.org/grpc/balancer/grpclb/grpc_lb_v1" @@ -125,13 +125,13 @@ func fakeNameDialer(addr string, timeout time.Duration) (net.Conn, error) { // merge merges the new client stats into current stats. // // It's a test-only method. rpcStats is defined in grpclb_picker. -func (s *rpcStats) merge(new *lbpb.ClientStats) { - atomic.AddInt64(&s.numCallsStarted, new.NumCallsStarted) - atomic.AddInt64(&s.numCallsFinished, new.NumCallsFinished) - atomic.AddInt64(&s.numCallsFinishedWithClientFailedToSend, new.NumCallsFinishedWithClientFailedToSend) - atomic.AddInt64(&s.numCallsFinishedKnownReceived, new.NumCallsFinishedKnownReceived) +func (s *rpcStats) merge(cs *lbpb.ClientStats) { + atomic.AddInt64(&s.numCallsStarted, cs.NumCallsStarted) + atomic.AddInt64(&s.numCallsFinished, cs.NumCallsFinished) + atomic.AddInt64(&s.numCallsFinishedWithClientFailedToSend, cs.NumCallsFinishedWithClientFailedToSend) + atomic.AddInt64(&s.numCallsFinishedKnownReceived, cs.NumCallsFinishedKnownReceived) s.mu.Lock() - for _, perToken := range new.CallsFinishedWithDrop { + for _, perToken := range cs.CallsFinishedWithDrop { s.numCallsDropped[perToken.LoadBalanceToken] += perToken.NumCalls } s.mu.Unlock() @@ -156,24 +156,24 @@ func atomicEqual(a, b *int64) bool { // equal compares two rpcStats. // // It's a test-only method. rpcStats is defined in grpclb_picker. -func (s *rpcStats) equal(new *rpcStats) bool { - if !atomicEqual(&s.numCallsStarted, &new.numCallsStarted) { +func (s *rpcStats) equal(o *rpcStats) bool { + if !atomicEqual(&s.numCallsStarted, &o.numCallsStarted) { return false } - if !atomicEqual(&s.numCallsFinished, &new.numCallsFinished) { + if !atomicEqual(&s.numCallsFinished, &o.numCallsFinished) { return false } - if !atomicEqual(&s.numCallsFinishedWithClientFailedToSend, &new.numCallsFinishedWithClientFailedToSend) { + if !atomicEqual(&s.numCallsFinishedWithClientFailedToSend, &o.numCallsFinishedWithClientFailedToSend) { return false } - if !atomicEqual(&s.numCallsFinishedKnownReceived, &new.numCallsFinishedKnownReceived) { + if !atomicEqual(&s.numCallsFinishedKnownReceived, &o.numCallsFinishedKnownReceived) { return false } s.mu.Lock() defer s.mu.Unlock() - new.mu.Lock() - defer new.mu.Unlock() - if !mapsEqual(s.numCallsDropped, new.numCallsDropped) { + o.mu.Lock() + defer o.mu.Unlock() + if !mapsEqual(s.numCallsDropped, o.numCallsDropped) { return false } return true diff --git a/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go b/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go index 2eda0a1c2107c667821fa3ee2a39bfdb8daa2213..57aea9fb4d2d28275d4d04cf5ce6b45b87cb91b9 100644 --- a/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go +++ b/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go @@ -22,9 +22,9 @@ package roundrobin import ( + "context" "sync" - "golang.org/x/net/context" "google.golang.org/grpc/balancer" "google.golang.org/grpc/balancer/base" "google.golang.org/grpc/grpclog" @@ -36,7 +36,7 @@ const Name = "round_robin" // newBuilder creates a new roundrobin balancer builder. func newBuilder() balancer.Builder { - return base.NewBalancerBuilder(Name, &rrPickerBuilder{}) + return base.NewBalancerBuilderWithConfig(Name, &rrPickerBuilder{}, base.Config{HealthCheck: true}) } func init() { diff --git a/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin_test.go b/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin_test.go index 70d8af7166ce1df4f868233e07503561ceb6e504..80c4e2b609a453cb23f550ddcfa60e74b2ff42dc 100644 --- a/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin_test.go +++ b/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin_test.go @@ -19,13 +19,13 @@ package roundrobin_test import ( + "context" "fmt" "net" "sync" "testing" "time" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/balancer/roundrobin" "google.golang.org/grpc/codes" diff --git a/vendor/google.golang.org/grpc/balancer_conn_wrappers.go b/vendor/google.golang.org/grpc/balancer_conn_wrappers.go index c23f81706fba24ce9c12ff88879fdc8af8dd1c1a..77b68477564af66a9a48bab41c32abb1f4be351b 100644 --- a/vendor/google.golang.org/grpc/balancer_conn_wrappers.go +++ b/vendor/google.golang.org/grpc/balancer_conn_wrappers.go @@ -197,7 +197,7 @@ func (ccb *ccBalancerWrapper) NewSubConn(addrs []resolver.Address, opts balancer if ccb.subConns == nil { return nil, fmt.Errorf("grpc: ClientConn balancer wrapper was closed") } - ac, err := ccb.cc.newAddrConn(addrs) + ac, err := ccb.cc.newAddrConn(addrs, opts) if err != nil { return nil, err } @@ -229,8 +229,13 @@ func (ccb *ccBalancerWrapper) UpdateBalancerState(s connectivity.State, p balanc if ccb.subConns == nil { return } - ccb.cc.csMgr.updateState(s) + // Update picker before updating state. Even though the ordering here does + // not matter, it can lead to multiple calls of Pick in the common start-up + // case where we wait for ready and then perform an RPC. If the picker is + // updated later, we could call the "connecting" picker when the state is + // updated, and then call the "ready" picker after the picker gets updated. ccb.cc.blockingpicker.updatePicker(p) + ccb.cc.csMgr.updateState(s) } func (ccb *ccBalancerWrapper) ResolveNow(o resolver.ResolveNowOption) { @@ -257,6 +262,7 @@ func (acbw *acBalancerWrapper) UpdateAddresses(addrs []resolver.Address) { } if !acbw.ac.tryUpdateAddrs(addrs) { cc := acbw.ac.cc + opts := acbw.ac.scopts acbw.ac.mu.Lock() // Set old ac.acbw to nil so the Shutdown state update will be ignored // by balancer. @@ -272,7 +278,7 @@ func (acbw *acBalancerWrapper) UpdateAddresses(addrs []resolver.Address) { return } - ac, err := cc.newAddrConn(addrs) + ac, err := cc.newAddrConn(addrs, opts) if err != nil { grpclog.Warningf("acBalancerWrapper: UpdateAddresses: failed to newAddrConn: %v", err) return diff --git a/vendor/google.golang.org/grpc/balancer_switching_test.go b/vendor/google.golang.org/grpc/balancer_switching_test.go index 0dcd9165c1b224a1b85384bc3d1ba455242e6014..d36c8e96ed64e279093e45a252d0c56c7ffcfe2e 100644 --- a/vendor/google.golang.org/grpc/balancer_switching_test.go +++ b/vendor/google.golang.org/grpc/balancer_switching_test.go @@ -19,12 +19,12 @@ package grpc import ( + "context" "fmt" "math" "testing" "time" - "golang.org/x/net/context" "google.golang.org/grpc/balancer" "google.golang.org/grpc/balancer/roundrobin" "google.golang.org/grpc/connectivity" diff --git a/vendor/google.golang.org/grpc/balancer_test.go b/vendor/google.golang.org/grpc/balancer_test.go index 8675e7d5efa783faf46dd88a4beb0718303aa7c7..219dcacac1791beb0a4d61d7db31e1701e9f83c6 100644 --- a/vendor/google.golang.org/grpc/balancer_test.go +++ b/vendor/google.golang.org/grpc/balancer_test.go @@ -19,6 +19,7 @@ package grpc import ( + "context" "fmt" "math" "strconv" @@ -26,7 +27,6 @@ import ( "testing" "time" - "golang.org/x/net/context" "google.golang.org/grpc/codes" _ "google.golang.org/grpc/grpclog/glogger" "google.golang.org/grpc/internal/leakcheck" @@ -39,6 +39,10 @@ import ( _ "google.golang.org/grpc/resolver/passthrough" ) +func pickFirstBalancerV1(r naming.Resolver) Balancer { + return &pickFirst{&roundRobin{r: r}} +} + type testWatcher struct { // the channel to receives name resolution updates update chan *naming.Update diff --git a/vendor/google.golang.org/grpc/balancer_v1_wrapper.go b/vendor/google.golang.org/grpc/balancer_v1_wrapper.go index e0ce32cfb6d42ccfdc8d2f2ffc0695e7d455443e..ca07c154b2d4ff98f19aa8ae11c9d0b75b21ea82 100644 --- a/vendor/google.golang.org/grpc/balancer_v1_wrapper.go +++ b/vendor/google.golang.org/grpc/balancer_v1_wrapper.go @@ -19,10 +19,10 @@ package grpc import ( + "context" "strings" "sync" - "golang.org/x/net/context" "google.golang.org/grpc/balancer" "google.golang.org/grpc/codes" "google.golang.org/grpc/connectivity" diff --git a/vendor/google.golang.org/grpc/benchmark/benchmain/main.go b/vendor/google.golang.org/grpc/benchmark/benchmain/main.go index 5a9e478d2c2f232e19687acfb6a42726baa3ac6e..9cb329f0be28db007fd384fb39192fa7d285b612 100644 --- a/vendor/google.golang.org/grpc/benchmark/benchmain/main.go +++ b/vendor/google.golang.org/grpc/benchmark/benchmain/main.go @@ -40,6 +40,7 @@ Assume there are two result files names as "basePerf" and "curPerf" created by a package main import ( + "context" "encoding/gob" "errors" "flag" @@ -59,13 +60,13 @@ import ( "testing" "time" - "golang.org/x/net/context" "google.golang.org/grpc" bm "google.golang.org/grpc/benchmark" testpb "google.golang.org/grpc/benchmark/grpc_testing" "google.golang.org/grpc/benchmark/latency" "google.golang.org/grpc/benchmark/stats" "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/internal/channelz" "google.golang.org/grpc/test/bufconn" ) @@ -113,14 +114,14 @@ var ( ) func unaryBenchmark(startTimer func(), stopTimer func(int32), benchFeatures stats.Features, benchtime time.Duration, s *stats.Stats) { - caller, close := makeFuncUnary(benchFeatures) - defer close() + caller, cleanup := makeFuncUnary(benchFeatures) + defer cleanup() runBenchmark(caller, startTimer, stopTimer, benchFeatures, benchtime, s) } func streamBenchmark(startTimer func(), stopTimer func(int32), benchFeatures stats.Features, benchtime time.Duration, s *stats.Stats) { - caller, close := makeFuncStream(benchFeatures) - defer close() + caller, cleanup := makeFuncStream(benchFeatures) + defer cleanup() runBenchmark(caller, startTimer, stopTimer, benchFeatures, benchtime, s) } @@ -452,7 +453,7 @@ func main() { grpc.EnableTracing = enableTrace[featuresPos[0]] if enableChannelz[featuresPos[8]] { - grpc.RegisterChannelz() + channelz.TurnOn() } if runMode[0] { unaryBenchmark(startTimer, stopTimer, benchFeature, benchtime, s) diff --git a/vendor/google.golang.org/grpc/benchmark/benchmark.go b/vendor/google.golang.org/grpc/benchmark/benchmark.go index ec9b50b2fe47e682414129dbb8f9cb5997a3f78a..e9a2723495ebe4a59e9fc52f7c06b687f2b657de 100644 --- a/vendor/google.golang.org/grpc/benchmark/benchmark.go +++ b/vendor/google.golang.org/grpc/benchmark/benchmark.go @@ -24,6 +24,7 @@ Package benchmark implements the building blocks to setup end-to-end gRPC benchm package benchmark import ( + "context" "fmt" "io" "net" @@ -31,7 +32,6 @@ import ( "testing" "time" - "golang.org/x/net/context" "google.golang.org/grpc" testpb "google.golang.org/grpc/benchmark/grpc_testing" "google.golang.org/grpc/benchmark/latency" diff --git a/vendor/google.golang.org/grpc/benchmark/benchmark16_test.go b/vendor/google.golang.org/grpc/benchmark/benchmark16_test.go deleted file mode 100644 index a036b63cbafb6470227a6cec34535f35634529dc..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/benchmark/benchmark16_test.go +++ /dev/null @@ -1,112 +0,0 @@ -// +build go1.6,!go1.7 - -/* - * - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package benchmark - -import ( - "os" - "testing" - - "google.golang.org/grpc" - "google.golang.org/grpc/benchmark/stats" -) - -func BenchmarkClientStreamc1(b *testing.B) { - grpc.EnableTracing = true - runStream(b, stats.Features{"", true, 0, 0, 0, 1, 1, 1, false, false}) -} - -func BenchmarkClientStreamc8(b *testing.B) { - grpc.EnableTracing = true - runStream(b, stats.Features{"", true, 0, 0, 0, 8, 1, 1, false, false}) -} - -func BenchmarkClientStreamc64(b *testing.B) { - grpc.EnableTracing = true - runStream(b, stats.Features{"", true, 0, 0, 0, 64, 1, 1, false, false}) -} - -func BenchmarkClientStreamc512(b *testing.B) { - grpc.EnableTracing = true - runStream(b, stats.Features{"", true, 0, 0, 0, 512, 1, 1, false, false}) -} -func BenchmarkClientUnaryc1(b *testing.B) { - grpc.EnableTracing = true - runStream(b, stats.Features{"", true, 0, 0, 0, 1, 1, 1, false, false}) -} - -func BenchmarkClientUnaryc8(b *testing.B) { - grpc.EnableTracing = true - runStream(b, stats.Features{"", true, 0, 0, 0, 8, 1, 1, false, false}) -} - -func BenchmarkClientUnaryc64(b *testing.B) { - grpc.EnableTracing = true - runStream(b, stats.Features{"", true, 0, 0, 0, 64, 1, 1, false, false}) -} - -func BenchmarkClientUnaryc512(b *testing.B) { - grpc.EnableTracing = true - runStream(b, stats.Features{"", true, 0, 0, 0, 512, 1, 1, false, false}) -} - -func BenchmarkClientStreamNoTracec1(b *testing.B) { - grpc.EnableTracing = false - runStream(b, stats.Features{"", false, 0, 0, 0, 1, 1, 1, false, false}) -} - -func BenchmarkClientStreamNoTracec8(b *testing.B) { - grpc.EnableTracing = false - runStream(b, stats.Features{"", false, 0, 0, 0, 8, 1, 1, false, false}) -} - -func BenchmarkClientStreamNoTracec64(b *testing.B) { - grpc.EnableTracing = false - runStream(b, stats.Features{"", false, 0, 0, 0, 64, 1, 1, false, false}) -} - -func BenchmarkClientStreamNoTracec512(b *testing.B) { - grpc.EnableTracing = false - runStream(b, stats.Features{"", false, 0, 0, 0, 512, 1, 1, false, false}) -} -func BenchmarkClientUnaryNoTracec1(b *testing.B) { - grpc.EnableTracing = false - runStream(b, stats.Features{"", false, 0, 0, 0, 1, 1, 1, false, false}) -} - -func BenchmarkClientUnaryNoTracec8(b *testing.B) { - grpc.EnableTracing = false - runStream(b, stats.Features{"", false, 0, 0, 0, 8, 1, 1, false, false}) -} - -func BenchmarkClientUnaryNoTracec64(b *testing.B) { - grpc.EnableTracing = false - runStream(b, stats.Features{"", false, 0, 0, 0, 64, 1, 1, false, false}) -} - -func BenchmarkClientUnaryNoTracec512(b *testing.B) { - grpc.EnableTracing = false - runStream(b, stats.Features{"", false, 0, 0, 0, 512, 1, 1, false, false}) - runStream(b, stats.Features{"", false, 0, 0, 0, 512, 1, 1, false, false}) -} - -func TestMain(m *testing.M) { - os.Exit(stats.RunTestMain(m)) -} diff --git a/vendor/google.golang.org/grpc/benchmark/benchmark17_test.go b/vendor/google.golang.org/grpc/benchmark/benchmark_test.go similarity index 99% rename from vendor/google.golang.org/grpc/benchmark/benchmark17_test.go rename to vendor/google.golang.org/grpc/benchmark/benchmark_test.go index 8dc7d3c5588943635ae3caefbdb71c0ddde9c394..dd4984a26f60cc2e5d0ddd6887306b65d7a822cb 100644 --- a/vendor/google.golang.org/grpc/benchmark/benchmark17_test.go +++ b/vendor/google.golang.org/grpc/benchmark/benchmark_test.go @@ -1,5 +1,3 @@ -// +build go1.7 - /* * * Copyright 2017 gRPC authors. diff --git a/vendor/google.golang.org/grpc/benchmark/client/main.go b/vendor/google.golang.org/grpc/benchmark/client/main.go index 13a5fb3e64804a22573e8616dc881c6ad065f22f..1cb02ea16597815e4828ea81313f6e4bcf57e4a7 100644 --- a/vendor/google.golang.org/grpc/benchmark/client/main.go +++ b/vendor/google.golang.org/grpc/benchmark/client/main.go @@ -19,6 +19,7 @@ package main import ( + "context" "flag" "fmt" "os" @@ -27,13 +28,12 @@ import ( "sync" "time" - "golang.org/x/net/context" - "golang.org/x/sys/unix" "google.golang.org/grpc" "google.golang.org/grpc/benchmark" testpb "google.golang.org/grpc/benchmark/grpc_testing" "google.golang.org/grpc/benchmark/stats" "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/internal/syscall" ) var ( @@ -82,12 +82,12 @@ func main() { } defer cf.Close() pprof.StartCPUProfile(cf) - cpuBeg := getCPUTime() + cpuBeg := syscall.GetCPUTime() for _, cc := range ccs { runWithConn(cc, req, warmDeadline, endDeadline) } wg.Wait() - cpu := time.Duration(getCPUTime() - cpuBeg) + cpu := time.Duration(syscall.GetCPUTime() - cpuBeg) pprof.StopCPUProfile() mf, err := os.Create("/tmp/" + *testName + ".mem") if err != nil { @@ -185,11 +185,3 @@ func median(percentile float64, h *stats.Histogram) int64 { } panic("should have found a bound") } - -func getCPUTime() int64 { - var ts unix.Timespec - if err := unix.ClockGettime(unix.CLOCK_PROCESS_CPUTIME_ID, &ts); err != nil { - grpclog.Fatal(err) - } - return ts.Nano() -} diff --git a/vendor/google.golang.org/grpc/benchmark/grpc_testing/control.pb.go b/vendor/google.golang.org/grpc/benchmark/grpc_testing/control.pb.go index 22134427acbc0227d2cbac37182b126659a49001..3d125b31fb38823cedea57120a6e768bfd76cd79 100644 --- a/vendor/google.golang.org/grpc/benchmark/grpc_testing/control.pb.go +++ b/vendor/google.golang.org/grpc/benchmark/grpc_testing/control.pb.go @@ -337,24 +337,32 @@ type isLoadParams_Load interface { type LoadParams_ClosedLoop struct { ClosedLoop *ClosedLoopParams `protobuf:"bytes,1,opt,name=closed_loop,json=closedLoop,proto3,oneof"` } + type LoadParams_Poisson struct { Poisson *PoissonParams `protobuf:"bytes,2,opt,name=poisson,proto3,oneof"` } + type LoadParams_Uniform struct { Uniform *UniformParams `protobuf:"bytes,3,opt,name=uniform,proto3,oneof"` } + type LoadParams_Determ struct { Determ *DeterministicParams `protobuf:"bytes,4,opt,name=determ,proto3,oneof"` } + type LoadParams_Pareto struct { Pareto *ParetoParams `protobuf:"bytes,5,opt,name=pareto,proto3,oneof"` } func (*LoadParams_ClosedLoop) isLoadParams_Load() {} -func (*LoadParams_Poisson) isLoadParams_Load() {} -func (*LoadParams_Uniform) isLoadParams_Load() {} -func (*LoadParams_Determ) isLoadParams_Load() {} -func (*LoadParams_Pareto) isLoadParams_Load() {} + +func (*LoadParams_Poisson) isLoadParams_Load() {} + +func (*LoadParams_Uniform) isLoadParams_Load() {} + +func (*LoadParams_Determ) isLoadParams_Load() {} + +func (*LoadParams_Pareto) isLoadParams_Load() {} func (m *LoadParams) GetLoad() isLoadParams_Load { if m != nil { @@ -829,12 +837,14 @@ type isClientArgs_Argtype interface { type ClientArgs_Setup struct { Setup *ClientConfig `protobuf:"bytes,1,opt,name=setup,proto3,oneof"` } + type ClientArgs_Mark struct { Mark *Mark `protobuf:"bytes,2,opt,name=mark,proto3,oneof"` } func (*ClientArgs_Setup) isClientArgs_Argtype() {} -func (*ClientArgs_Mark) isClientArgs_Argtype() {} + +func (*ClientArgs_Mark) isClientArgs_Argtype() {} func (m *ClientArgs) GetArgtype() isClientArgs_Argtype { if m != nil { @@ -1063,12 +1073,14 @@ type isServerArgs_Argtype interface { type ServerArgs_Setup struct { Setup *ServerConfig `protobuf:"bytes,1,opt,name=setup,proto3,oneof"` } + type ServerArgs_Mark struct { Mark *Mark `protobuf:"bytes,2,opt,name=mark,proto3,oneof"` } func (*ServerArgs_Setup) isServerArgs_Argtype() {} -func (*ServerArgs_Mark) isServerArgs_Argtype() {} + +func (*ServerArgs_Mark) isServerArgs_Argtype() {} func (m *ServerArgs) GetArgtype() isServerArgs_Argtype { if m != nil { diff --git a/vendor/google.golang.org/grpc/benchmark/grpc_testing/payloads.pb.go b/vendor/google.golang.org/grpc/benchmark/grpc_testing/payloads.pb.go index 1882fe7e23a4064316dad4a655ca1a45dd3547b5..f7f9cf8eb4661db39b716c8808cc8fe8d2c71fc3 100644 --- a/vendor/google.golang.org/grpc/benchmark/grpc_testing/payloads.pb.go +++ b/vendor/google.golang.org/grpc/benchmark/grpc_testing/payloads.pb.go @@ -182,15 +182,19 @@ type isPayloadConfig_Payload interface { type PayloadConfig_BytebufParams struct { BytebufParams *ByteBufferParams `protobuf:"bytes,1,opt,name=bytebuf_params,json=bytebufParams,proto3,oneof"` } + type PayloadConfig_SimpleParams struct { SimpleParams *SimpleProtoParams `protobuf:"bytes,2,opt,name=simple_params,json=simpleParams,proto3,oneof"` } + type PayloadConfig_ComplexParams struct { ComplexParams *ComplexProtoParams `protobuf:"bytes,3,opt,name=complex_params,json=complexParams,proto3,oneof"` } func (*PayloadConfig_BytebufParams) isPayloadConfig_Payload() {} -func (*PayloadConfig_SimpleParams) isPayloadConfig_Payload() {} + +func (*PayloadConfig_SimpleParams) isPayloadConfig_Payload() {} + func (*PayloadConfig_ComplexParams) isPayloadConfig_Payload() {} func (m *PayloadConfig) GetPayload() isPayloadConfig_Payload { diff --git a/vendor/google.golang.org/grpc/benchmark/latency/latency.go b/vendor/google.golang.org/grpc/benchmark/latency/latency.go index 5839a5c4429acf1bbf93282a87d747b3d1959a78..d5cc44f9b5ee9fba29a08c51965d3f45fbfad874 100644 --- a/vendor/google.golang.org/grpc/benchmark/latency/latency.go +++ b/vendor/google.golang.org/grpc/benchmark/latency/latency.go @@ -23,13 +23,12 @@ package latency import ( "bytes" + "context" "encoding/binary" "fmt" "io" "net" "time" - - "golang.org/x/net/context" ) // Dialer is a function matching the signature of net.Dial. diff --git a/vendor/google.golang.org/grpc/benchmark/primitives/context_test.go b/vendor/google.golang.org/grpc/benchmark/primitives/context_test.go index e1d6c043f325b9b217fb35f5b8b730a9cd7a503f..1d92192f3438c3c2aaf7a5770f8ae9343b484963 100644 --- a/vendor/google.golang.org/grpc/benchmark/primitives/context_test.go +++ b/vendor/google.golang.org/grpc/benchmark/primitives/context_test.go @@ -19,10 +19,9 @@ package primitives_test import ( + "context" "testing" "time" - - "golang.org/x/net/context" ) func BenchmarkCancelContextErrNoErr(b *testing.B) { diff --git a/vendor/google.golang.org/grpc/benchmark/primitives/primitives_test.go b/vendor/google.golang.org/grpc/benchmark/primitives/primitives_test.go index 846813d8d174a5ad835e6ba5ba0f45f459105444..71fc26e294189b44753b2d21aa054be08158f532 100644 --- a/vendor/google.golang.org/grpc/benchmark/primitives/primitives_test.go +++ b/vendor/google.golang.org/grpc/benchmark/primitives/primitives_test.go @@ -1,5 +1,3 @@ -// +build go1.7 - /* * * Copyright 2017 gRPC authors. diff --git a/vendor/google.golang.org/grpc/benchmark/run_bench.sh b/vendor/google.golang.org/grpc/benchmark/run_bench.sh index 045de1602d686a7d72eeb328fafcfd8046d08a21..a79292b93ce093593731c8c1997a7d39c1fe10e2 100755 --- a/vendor/google.golang.org/grpc/benchmark/run_bench.sh +++ b/vendor/google.golang.org/grpc/benchmark/run_bench.sh @@ -72,7 +72,7 @@ run(){ ${out_dir}/client --port=${port} --d=${dur} --w=${warmup} --r=${nr} --c=${nc} --req=${req_sz} --resp=${resp_sz} --rpc_type=${r_type} --test_name="client_"${test_name} client_status=$(echo $?) - kill ${server_pid} + kill -INT ${server_pid} wait ${server_pid} if [ ${client_status} == 0 ]; then diff --git a/vendor/google.golang.org/grpc/benchmark/server/main.go b/vendor/google.golang.org/grpc/benchmark/server/main.go index 253657e0ecd3f940c8e73ac0f4054f72b44a53c1..fe1909442380e54ec3987de205ad57a7da318964 100644 --- a/vendor/google.golang.org/grpc/benchmark/server/main.go +++ b/vendor/google.golang.org/grpc/benchmark/server/main.go @@ -27,12 +27,11 @@ import ( "os/signal" "runtime" "runtime/pprof" - "syscall" "time" - "golang.org/x/sys/unix" "google.golang.org/grpc/benchmark" "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/internal/syscall" ) var ( @@ -57,14 +56,14 @@ func main() { } defer cf.Close() pprof.StartCPUProfile(cf) - cpuBeg := getCPUTime() + cpuBeg := syscall.GetCPUTime() // Launch server in a separate goroutine. stop := benchmark.StartServer(benchmark.ServerInfo{Type: "protobuf", Listener: lis}) // Wait on OS terminate signal. ch := make(chan os.Signal, 1) - signal.Notify(ch, syscall.SIGTERM) + signal.Notify(ch, os.Interrupt) <-ch - cpu := time.Duration(getCPUTime() - cpuBeg) + cpu := time.Duration(syscall.GetCPUTime() - cpuBeg) stop() pprof.StopCPUProfile() mf, err := os.Create("/tmp/" + *testName + ".mem") @@ -80,11 +79,3 @@ func main() { fmt.Println("Server CPU profile:", cf.Name()) fmt.Println("Server Mem Profile:", mf.Name()) } - -func getCPUTime() int64 { - var ts unix.Timespec - if err := unix.ClockGettime(unix.CLOCK_PROCESS_CPUTIME_ID, &ts); err != nil { - grpclog.Fatal(err) - } - return ts.Nano() -} diff --git a/vendor/google.golang.org/grpc/benchmark/worker/benchmark_client.go b/vendor/google.golang.org/grpc/benchmark/worker/benchmark_client.go index 56cf087f41982ee0e9b4bf68773b7a2a6a421494..abb5bc9928aa30d3feca8b923e3f37cee6b1fded 100644 --- a/vendor/google.golang.org/grpc/benchmark/worker/benchmark_client.go +++ b/vendor/google.golang.org/grpc/benchmark/worker/benchmark_client.go @@ -19,14 +19,13 @@ package main import ( + "context" "flag" "math" "runtime" "sync" - "syscall" "time" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/benchmark" testpb "google.golang.org/grpc/benchmark/grpc_testing" @@ -34,6 +33,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/internal/syscall" "google.golang.org/grpc/status" "google.golang.org/grpc/testdata" ) @@ -51,12 +51,12 @@ func (h *lockingHistogram) add(value int64) { h.histogram.Add(value) } -// swap sets h.histogram to new, and returns its old value. -func (h *lockingHistogram) swap(new *stats.Histogram) *stats.Histogram { +// swap sets h.histogram to o and returns its old value. +func (h *lockingHistogram) swap(o *stats.Histogram) *stats.Histogram { h.mu.Lock() defer h.mu.Unlock() old := h.histogram - h.histogram = new + h.histogram = o return old } @@ -217,9 +217,6 @@ func startBenchmarkClient(config *testpb.ClientConfig) (*benchmarkClient, error) return nil, err } - rusage := new(syscall.Rusage) - syscall.Getrusage(syscall.RUSAGE_SELF, rusage) - rpcCountPerConn := int(config.OutstandingRpcsPerChannel) bc := &benchmarkClient{ histogramOptions: stats.HistogramOptions{ @@ -233,7 +230,7 @@ func startBenchmarkClient(config *testpb.ClientConfig) (*benchmarkClient, error) stop: make(chan bool), lastResetTime: time.Now(), closeConns: closeConns, - rusageLastReset: rusage, + rusageLastReset: syscall.GetRusage(), } if err = performRPCs(config, conns, bc); err != nil { @@ -335,7 +332,6 @@ func (bc *benchmarkClient) doCloseLoopStreaming(conns []*grpc.ClientConn, rpcCou func (bc *benchmarkClient) getStats(reset bool) *testpb.ClientStats { var wallTimeElapsed, uTimeElapsed, sTimeElapsed float64 mergedHistogram := stats.NewHistogram(bc.histogramOptions) - latestRusage := new(syscall.Rusage) if reset { // Merging histogram may take some time. @@ -350,8 +346,8 @@ func (bc *benchmarkClient) getStats(reset bool) *testpb.ClientStats { } wallTimeElapsed = time.Since(bc.lastResetTime).Seconds() - syscall.Getrusage(syscall.RUSAGE_SELF, latestRusage) - uTimeElapsed, sTimeElapsed = cpuTimeDiff(bc.rusageLastReset, latestRusage) + latestRusage := syscall.GetRusage() + uTimeElapsed, sTimeElapsed = syscall.CPUTimeDiff(bc.rusageLastReset, latestRusage) bc.rusageLastReset = latestRusage bc.lastResetTime = time.Now() @@ -362,8 +358,7 @@ func (bc *benchmarkClient) getStats(reset bool) *testpb.ClientStats { } wallTimeElapsed = time.Since(bc.lastResetTime).Seconds() - syscall.Getrusage(syscall.RUSAGE_SELF, latestRusage) - uTimeElapsed, sTimeElapsed = cpuTimeDiff(bc.rusageLastReset, latestRusage) + uTimeElapsed, sTimeElapsed = syscall.CPUTimeDiff(bc.rusageLastReset, syscall.GetRusage()) } b := make([]uint32, len(mergedHistogram.Buckets)) diff --git a/vendor/google.golang.org/grpc/benchmark/worker/benchmark_server.go b/vendor/google.golang.org/grpc/benchmark/worker/benchmark_server.go index 9b1f676fa458730edff6a985ff011608b53c2fef..56f7e6ee265f6fa434215b5acca14805449695b0 100644 --- a/vendor/google.golang.org/grpc/benchmark/worker/benchmark_server.go +++ b/vendor/google.golang.org/grpc/benchmark/worker/benchmark_server.go @@ -26,7 +26,6 @@ import ( "strconv" "strings" "sync" - "syscall" "time" "google.golang.org/grpc" @@ -35,6 +34,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/internal/syscall" "google.golang.org/grpc/status" "google.golang.org/grpc/testdata" ) @@ -154,15 +154,12 @@ func startBenchmarkServer(config *testpb.ServerConfig, serverPort int) (*benchma grpclog.Fatalf("failed to get port number from server address: %v", err) } - rusage := new(syscall.Rusage) - syscall.Getrusage(syscall.RUSAGE_SELF, rusage) - return &benchmarkServer{ port: p, cores: numOfCores, closeFunc: closeFunc, lastResetTime: time.Now(), - rusageLastReset: rusage, + rusageLastReset: syscall.GetRusage(), }, nil } @@ -172,9 +169,8 @@ func (bs *benchmarkServer) getStats(reset bool) *testpb.ServerStats { bs.mu.RLock() defer bs.mu.RUnlock() wallTimeElapsed := time.Since(bs.lastResetTime).Seconds() - rusageLatest := new(syscall.Rusage) - syscall.Getrusage(syscall.RUSAGE_SELF, rusageLatest) - uTimeElapsed, sTimeElapsed := cpuTimeDiff(bs.rusageLastReset, rusageLatest) + rusageLatest := syscall.GetRusage() + uTimeElapsed, sTimeElapsed := syscall.CPUTimeDiff(bs.rusageLastReset, rusageLatest) if reset { bs.lastResetTime = time.Now() diff --git a/vendor/google.golang.org/grpc/benchmark/worker/main.go b/vendor/google.golang.org/grpc/benchmark/worker/main.go index 3d2fd6173d9223741ebb509f7e0c66751faf5652..5933bd3ac7a1ef634aa548b6fbae2879a22b3c43 100644 --- a/vendor/google.golang.org/grpc/benchmark/worker/main.go +++ b/vendor/google.golang.org/grpc/benchmark/worker/main.go @@ -19,6 +19,7 @@ package main import ( + "context" "flag" "fmt" "io" @@ -29,7 +30,6 @@ import ( "strconv" "time" - "golang.org/x/net/context" "google.golang.org/grpc" testpb "google.golang.org/grpc/benchmark/grpc_testing" "google.golang.org/grpc/codes" diff --git a/vendor/google.golang.org/grpc/benchmark/worker/util.go b/vendor/google.golang.org/grpc/benchmark/worker/util.go deleted file mode 100644 index f26993e6540b416956a645d242282dbb507ef63b..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/benchmark/worker/util.go +++ /dev/null @@ -1,35 +0,0 @@ -/* - * - * Copyright 2016 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package main - -import "syscall" - -func cpuTimeDiff(first *syscall.Rusage, latest *syscall.Rusage) (float64, float64) { - var ( - utimeDiffs = latest.Utime.Sec - first.Utime.Sec - utimeDiffus = latest.Utime.Usec - first.Utime.Usec - stimeDiffs = latest.Stime.Sec - first.Stime.Sec - stimeDiffus = latest.Stime.Usec - first.Stime.Usec - ) - - uTimeElapsed := float64(utimeDiffs) + float64(utimeDiffus)*1.0e-6 - sTimeElapsed := float64(stimeDiffs) + float64(stimeDiffus)*1.0e-6 - - return uTimeElapsed, sTimeElapsed -} diff --git a/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..f393bb66187e8eb02f3eb4170092785c7caa6e3f --- /dev/null +++ b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go @@ -0,0 +1,900 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: grpc/binarylog/grpc_binarylog_v1/binarylog.proto + +package grpc_binarylog_v1 // import "google.golang.org/grpc/binarylog/grpc_binarylog_v1" + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import duration "github.com/golang/protobuf/ptypes/duration" +import timestamp "github.com/golang/protobuf/ptypes/timestamp" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// Enumerates the type of event +// Note the terminology is different from the RPC semantics +// definition, but the same meaning is expressed here. +type GrpcLogEntry_EventType int32 + +const ( + GrpcLogEntry_EVENT_TYPE_UNKNOWN GrpcLogEntry_EventType = 0 + // Header sent from client to server + GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER GrpcLogEntry_EventType = 1 + // Header sent from server to client + GrpcLogEntry_EVENT_TYPE_SERVER_HEADER GrpcLogEntry_EventType = 2 + // Message sent from client to server + GrpcLogEntry_EVENT_TYPE_CLIENT_MESSAGE GrpcLogEntry_EventType = 3 + // Message sent from server to client + GrpcLogEntry_EVENT_TYPE_SERVER_MESSAGE GrpcLogEntry_EventType = 4 + // A signal that client is done sending + GrpcLogEntry_EVENT_TYPE_CLIENT_HALF_CLOSE GrpcLogEntry_EventType = 5 + // Trailer indicates the end of the RPC. + // On client side, this event means a trailer was either received + // from the network or the gRPC library locally generated a status + // to inform the application about a failure. + // On server side, this event means the server application requested + // to send a trailer. Note: EVENT_TYPE_CANCEL may still arrive after + // this due to races on server side. + GrpcLogEntry_EVENT_TYPE_SERVER_TRAILER GrpcLogEntry_EventType = 6 + // A signal that the RPC is cancelled. On client side, this + // indicates the client application requests a cancellation. + // On server side, this indicates that cancellation was detected. + // Note: This marks the end of the RPC. Events may arrive after + // this due to races. For example, on client side a trailer + // may arrive even though the application requested to cancel the RPC. + GrpcLogEntry_EVENT_TYPE_CANCEL GrpcLogEntry_EventType = 7 +) + +var GrpcLogEntry_EventType_name = map[int32]string{ + 0: "EVENT_TYPE_UNKNOWN", + 1: "EVENT_TYPE_CLIENT_HEADER", + 2: "EVENT_TYPE_SERVER_HEADER", + 3: "EVENT_TYPE_CLIENT_MESSAGE", + 4: "EVENT_TYPE_SERVER_MESSAGE", + 5: "EVENT_TYPE_CLIENT_HALF_CLOSE", + 6: "EVENT_TYPE_SERVER_TRAILER", + 7: "EVENT_TYPE_CANCEL", +} +var GrpcLogEntry_EventType_value = map[string]int32{ + "EVENT_TYPE_UNKNOWN": 0, + "EVENT_TYPE_CLIENT_HEADER": 1, + "EVENT_TYPE_SERVER_HEADER": 2, + "EVENT_TYPE_CLIENT_MESSAGE": 3, + "EVENT_TYPE_SERVER_MESSAGE": 4, + "EVENT_TYPE_CLIENT_HALF_CLOSE": 5, + "EVENT_TYPE_SERVER_TRAILER": 6, + "EVENT_TYPE_CANCEL": 7, +} + +func (x GrpcLogEntry_EventType) String() string { + return proto.EnumName(GrpcLogEntry_EventType_name, int32(x)) +} +func (GrpcLogEntry_EventType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_binarylog_264c8c9c551ce911, []int{0, 0} +} + +// Enumerates the entity that generates the log entry +type GrpcLogEntry_Logger int32 + +const ( + GrpcLogEntry_LOGGER_UNKNOWN GrpcLogEntry_Logger = 0 + GrpcLogEntry_LOGGER_CLIENT GrpcLogEntry_Logger = 1 + GrpcLogEntry_LOGGER_SERVER GrpcLogEntry_Logger = 2 +) + +var GrpcLogEntry_Logger_name = map[int32]string{ + 0: "LOGGER_UNKNOWN", + 1: "LOGGER_CLIENT", + 2: "LOGGER_SERVER", +} +var GrpcLogEntry_Logger_value = map[string]int32{ + "LOGGER_UNKNOWN": 0, + "LOGGER_CLIENT": 1, + "LOGGER_SERVER": 2, +} + +func (x GrpcLogEntry_Logger) String() string { + return proto.EnumName(GrpcLogEntry_Logger_name, int32(x)) +} +func (GrpcLogEntry_Logger) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_binarylog_264c8c9c551ce911, []int{0, 1} +} + +type Address_Type int32 + +const ( + Address_TYPE_UNKNOWN Address_Type = 0 + // address is in 1.2.3.4 form + Address_TYPE_IPV4 Address_Type = 1 + // address is in IPv6 canonical form (RFC5952 section 4) + // The scope is NOT included in the address string. + Address_TYPE_IPV6 Address_Type = 2 + // address is UDS string + Address_TYPE_UNIX Address_Type = 3 +) + +var Address_Type_name = map[int32]string{ + 0: "TYPE_UNKNOWN", + 1: "TYPE_IPV4", + 2: "TYPE_IPV6", + 3: "TYPE_UNIX", +} +var Address_Type_value = map[string]int32{ + "TYPE_UNKNOWN": 0, + "TYPE_IPV4": 1, + "TYPE_IPV6": 2, + "TYPE_UNIX": 3, +} + +func (x Address_Type) String() string { + return proto.EnumName(Address_Type_name, int32(x)) +} +func (Address_Type) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_binarylog_264c8c9c551ce911, []int{7, 0} +} + +// Log entry we store in binary logs +type GrpcLogEntry struct { + // The timestamp of the binary log message + Timestamp *timestamp.Timestamp `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + // Uniquely identifies a call. The value must not be 0 in order to disambiguate + // from an unset value. + // Each call may have several log entries, they will all have the same call_id. + // Nothing is guaranteed about their value other than they are unique across + // different RPCs in the same gRPC process. + CallId uint64 `protobuf:"varint,2,opt,name=call_id,json=callId,proto3" json:"call_id,omitempty"` + // The entry sequence id for this call. The first GrpcLogEntry has a + // value of 1, to disambiguate from an unset value. The purpose of + // this field is to detect missing entries in environments where + // durability or ordering is not guaranteed. + SequenceIdWithinCall uint64 `protobuf:"varint,3,opt,name=sequence_id_within_call,json=sequenceIdWithinCall,proto3" json:"sequence_id_within_call,omitempty"` + Type GrpcLogEntry_EventType `protobuf:"varint,4,opt,name=type,proto3,enum=grpc.binarylog.v1.GrpcLogEntry_EventType" json:"type,omitempty"` + Logger GrpcLogEntry_Logger `protobuf:"varint,5,opt,name=logger,proto3,enum=grpc.binarylog.v1.GrpcLogEntry_Logger" json:"logger,omitempty"` + // The logger uses one of the following fields to record the payload, + // according to the type of the log entry. + // + // Types that are valid to be assigned to Payload: + // *GrpcLogEntry_ClientHeader + // *GrpcLogEntry_ServerHeader + // *GrpcLogEntry_Message + // *GrpcLogEntry_Trailer + Payload isGrpcLogEntry_Payload `protobuf_oneof:"payload"` + // true if payload does not represent the full message or metadata. + PayloadTruncated bool `protobuf:"varint,10,opt,name=payload_truncated,json=payloadTruncated,proto3" json:"payload_truncated,omitempty"` + // Peer address information, will only be recorded on the first + // incoming event. On client side, peer is logged on + // EVENT_TYPE_SERVER_HEADER normally or EVENT_TYPE_SERVER_TRAILER in + // the case of trailers-only. On server side, peer is always + // logged on EVENT_TYPE_CLIENT_HEADER. + Peer *Address `protobuf:"bytes,11,opt,name=peer,proto3" json:"peer,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GrpcLogEntry) Reset() { *m = GrpcLogEntry{} } +func (m *GrpcLogEntry) String() string { return proto.CompactTextString(m) } +func (*GrpcLogEntry) ProtoMessage() {} +func (*GrpcLogEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_binarylog_264c8c9c551ce911, []int{0} +} +func (m *GrpcLogEntry) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GrpcLogEntry.Unmarshal(m, b) +} +func (m *GrpcLogEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GrpcLogEntry.Marshal(b, m, deterministic) +} +func (dst *GrpcLogEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_GrpcLogEntry.Merge(dst, src) +} +func (m *GrpcLogEntry) XXX_Size() int { + return xxx_messageInfo_GrpcLogEntry.Size(m) +} +func (m *GrpcLogEntry) XXX_DiscardUnknown() { + xxx_messageInfo_GrpcLogEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_GrpcLogEntry proto.InternalMessageInfo + +func (m *GrpcLogEntry) GetTimestamp() *timestamp.Timestamp { + if m != nil { + return m.Timestamp + } + return nil +} + +func (m *GrpcLogEntry) GetCallId() uint64 { + if m != nil { + return m.CallId + } + return 0 +} + +func (m *GrpcLogEntry) GetSequenceIdWithinCall() uint64 { + if m != nil { + return m.SequenceIdWithinCall + } + return 0 +} + +func (m *GrpcLogEntry) GetType() GrpcLogEntry_EventType { + if m != nil { + return m.Type + } + return GrpcLogEntry_EVENT_TYPE_UNKNOWN +} + +func (m *GrpcLogEntry) GetLogger() GrpcLogEntry_Logger { + if m != nil { + return m.Logger + } + return GrpcLogEntry_LOGGER_UNKNOWN +} + +type isGrpcLogEntry_Payload interface { + isGrpcLogEntry_Payload() +} + +type GrpcLogEntry_ClientHeader struct { + ClientHeader *ClientHeader `protobuf:"bytes,6,opt,name=client_header,json=clientHeader,proto3,oneof"` +} + +type GrpcLogEntry_ServerHeader struct { + ServerHeader *ServerHeader `protobuf:"bytes,7,opt,name=server_header,json=serverHeader,proto3,oneof"` +} + +type GrpcLogEntry_Message struct { + Message *Message `protobuf:"bytes,8,opt,name=message,proto3,oneof"` +} + +type GrpcLogEntry_Trailer struct { + Trailer *Trailer `protobuf:"bytes,9,opt,name=trailer,proto3,oneof"` +} + +func (*GrpcLogEntry_ClientHeader) isGrpcLogEntry_Payload() {} + +func (*GrpcLogEntry_ServerHeader) isGrpcLogEntry_Payload() {} + +func (*GrpcLogEntry_Message) isGrpcLogEntry_Payload() {} + +func (*GrpcLogEntry_Trailer) isGrpcLogEntry_Payload() {} + +func (m *GrpcLogEntry) GetPayload() isGrpcLogEntry_Payload { + if m != nil { + return m.Payload + } + return nil +} + +func (m *GrpcLogEntry) GetClientHeader() *ClientHeader { + if x, ok := m.GetPayload().(*GrpcLogEntry_ClientHeader); ok { + return x.ClientHeader + } + return nil +} + +func (m *GrpcLogEntry) GetServerHeader() *ServerHeader { + if x, ok := m.GetPayload().(*GrpcLogEntry_ServerHeader); ok { + return x.ServerHeader + } + return nil +} + +func (m *GrpcLogEntry) GetMessage() *Message { + if x, ok := m.GetPayload().(*GrpcLogEntry_Message); ok { + return x.Message + } + return nil +} + +func (m *GrpcLogEntry) GetTrailer() *Trailer { + if x, ok := m.GetPayload().(*GrpcLogEntry_Trailer); ok { + return x.Trailer + } + return nil +} + +func (m *GrpcLogEntry) GetPayloadTruncated() bool { + if m != nil { + return m.PayloadTruncated + } + return false +} + +func (m *GrpcLogEntry) GetPeer() *Address { + if m != nil { + return m.Peer + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*GrpcLogEntry) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _GrpcLogEntry_OneofMarshaler, _GrpcLogEntry_OneofUnmarshaler, _GrpcLogEntry_OneofSizer, []interface{}{ + (*GrpcLogEntry_ClientHeader)(nil), + (*GrpcLogEntry_ServerHeader)(nil), + (*GrpcLogEntry_Message)(nil), + (*GrpcLogEntry_Trailer)(nil), + } +} + +func _GrpcLogEntry_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*GrpcLogEntry) + // payload + switch x := m.Payload.(type) { + case *GrpcLogEntry_ClientHeader: + b.EncodeVarint(6<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.ClientHeader); err != nil { + return err + } + case *GrpcLogEntry_ServerHeader: + b.EncodeVarint(7<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.ServerHeader); err != nil { + return err + } + case *GrpcLogEntry_Message: + b.EncodeVarint(8<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Message); err != nil { + return err + } + case *GrpcLogEntry_Trailer: + b.EncodeVarint(9<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Trailer); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("GrpcLogEntry.Payload has unexpected type %T", x) + } + return nil +} + +func _GrpcLogEntry_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*GrpcLogEntry) + switch tag { + case 6: // payload.client_header + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(ClientHeader) + err := b.DecodeMessage(msg) + m.Payload = &GrpcLogEntry_ClientHeader{msg} + return true, err + case 7: // payload.server_header + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(ServerHeader) + err := b.DecodeMessage(msg) + m.Payload = &GrpcLogEntry_ServerHeader{msg} + return true, err + case 8: // payload.message + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Message) + err := b.DecodeMessage(msg) + m.Payload = &GrpcLogEntry_Message{msg} + return true, err + case 9: // payload.trailer + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Trailer) + err := b.DecodeMessage(msg) + m.Payload = &GrpcLogEntry_Trailer{msg} + return true, err + default: + return false, nil + } +} + +func _GrpcLogEntry_OneofSizer(msg proto.Message) (n int) { + m := msg.(*GrpcLogEntry) + // payload + switch x := m.Payload.(type) { + case *GrpcLogEntry_ClientHeader: + s := proto.Size(x.ClientHeader) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *GrpcLogEntry_ServerHeader: + s := proto.Size(x.ServerHeader) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *GrpcLogEntry_Message: + s := proto.Size(x.Message) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *GrpcLogEntry_Trailer: + s := proto.Size(x.Trailer) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +type ClientHeader struct { + // This contains only the metadata from the application. + Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + // The name of the RPC method, which looks something like: + // // + // Note the leading "/" character. + MethodName string `protobuf:"bytes,2,opt,name=method_name,json=methodName,proto3" json:"method_name,omitempty"` + // A single process may be used to run multiple virtual + // servers with different identities. + // The authority is the name of such a server identitiy. + // It is typically a portion of the URI in the form of + // or : . + Authority string `protobuf:"bytes,3,opt,name=authority,proto3" json:"authority,omitempty"` + // the RPC timeout + Timeout *duration.Duration `protobuf:"bytes,4,opt,name=timeout,proto3" json:"timeout,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ClientHeader) Reset() { *m = ClientHeader{} } +func (m *ClientHeader) String() string { return proto.CompactTextString(m) } +func (*ClientHeader) ProtoMessage() {} +func (*ClientHeader) Descriptor() ([]byte, []int) { + return fileDescriptor_binarylog_264c8c9c551ce911, []int{1} +} +func (m *ClientHeader) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ClientHeader.Unmarshal(m, b) +} +func (m *ClientHeader) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ClientHeader.Marshal(b, m, deterministic) +} +func (dst *ClientHeader) XXX_Merge(src proto.Message) { + xxx_messageInfo_ClientHeader.Merge(dst, src) +} +func (m *ClientHeader) XXX_Size() int { + return xxx_messageInfo_ClientHeader.Size(m) +} +func (m *ClientHeader) XXX_DiscardUnknown() { + xxx_messageInfo_ClientHeader.DiscardUnknown(m) +} + +var xxx_messageInfo_ClientHeader proto.InternalMessageInfo + +func (m *ClientHeader) GetMetadata() *Metadata { + if m != nil { + return m.Metadata + } + return nil +} + +func (m *ClientHeader) GetMethodName() string { + if m != nil { + return m.MethodName + } + return "" +} + +func (m *ClientHeader) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *ClientHeader) GetTimeout() *duration.Duration { + if m != nil { + return m.Timeout + } + return nil +} + +type ServerHeader struct { + // This contains only the metadata from the application. + Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ServerHeader) Reset() { *m = ServerHeader{} } +func (m *ServerHeader) String() string { return proto.CompactTextString(m) } +func (*ServerHeader) ProtoMessage() {} +func (*ServerHeader) Descriptor() ([]byte, []int) { + return fileDescriptor_binarylog_264c8c9c551ce911, []int{2} +} +func (m *ServerHeader) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ServerHeader.Unmarshal(m, b) +} +func (m *ServerHeader) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ServerHeader.Marshal(b, m, deterministic) +} +func (dst *ServerHeader) XXX_Merge(src proto.Message) { + xxx_messageInfo_ServerHeader.Merge(dst, src) +} +func (m *ServerHeader) XXX_Size() int { + return xxx_messageInfo_ServerHeader.Size(m) +} +func (m *ServerHeader) XXX_DiscardUnknown() { + xxx_messageInfo_ServerHeader.DiscardUnknown(m) +} + +var xxx_messageInfo_ServerHeader proto.InternalMessageInfo + +func (m *ServerHeader) GetMetadata() *Metadata { + if m != nil { + return m.Metadata + } + return nil +} + +type Trailer struct { + // This contains only the metadata from the application. + Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + // The gRPC status code. + StatusCode uint32 `protobuf:"varint,2,opt,name=status_code,json=statusCode,proto3" json:"status_code,omitempty"` + // An original status message before any transport specific + // encoding. + StatusMessage string `protobuf:"bytes,3,opt,name=status_message,json=statusMessage,proto3" json:"status_message,omitempty"` + // The value of the 'grpc-status-details-bin' metadata key. If + // present, this is always an encoded 'google.rpc.Status' message. + StatusDetails []byte `protobuf:"bytes,4,opt,name=status_details,json=statusDetails,proto3" json:"status_details,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Trailer) Reset() { *m = Trailer{} } +func (m *Trailer) String() string { return proto.CompactTextString(m) } +func (*Trailer) ProtoMessage() {} +func (*Trailer) Descriptor() ([]byte, []int) { + return fileDescriptor_binarylog_264c8c9c551ce911, []int{3} +} +func (m *Trailer) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Trailer.Unmarshal(m, b) +} +func (m *Trailer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Trailer.Marshal(b, m, deterministic) +} +func (dst *Trailer) XXX_Merge(src proto.Message) { + xxx_messageInfo_Trailer.Merge(dst, src) +} +func (m *Trailer) XXX_Size() int { + return xxx_messageInfo_Trailer.Size(m) +} +func (m *Trailer) XXX_DiscardUnknown() { + xxx_messageInfo_Trailer.DiscardUnknown(m) +} + +var xxx_messageInfo_Trailer proto.InternalMessageInfo + +func (m *Trailer) GetMetadata() *Metadata { + if m != nil { + return m.Metadata + } + return nil +} + +func (m *Trailer) GetStatusCode() uint32 { + if m != nil { + return m.StatusCode + } + return 0 +} + +func (m *Trailer) GetStatusMessage() string { + if m != nil { + return m.StatusMessage + } + return "" +} + +func (m *Trailer) GetStatusDetails() []byte { + if m != nil { + return m.StatusDetails + } + return nil +} + +// Message payload, used by CLIENT_MESSAGE and SERVER_MESSAGE +type Message struct { + // Length of the message. It may not be the same as the length of the + // data field, as the logging payload can be truncated or omitted. + Length uint32 `protobuf:"varint,1,opt,name=length,proto3" json:"length,omitempty"` + // May be truncated or omitted. + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Message) Reset() { *m = Message{} } +func (m *Message) String() string { return proto.CompactTextString(m) } +func (*Message) ProtoMessage() {} +func (*Message) Descriptor() ([]byte, []int) { + return fileDescriptor_binarylog_264c8c9c551ce911, []int{4} +} +func (m *Message) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Message.Unmarshal(m, b) +} +func (m *Message) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Message.Marshal(b, m, deterministic) +} +func (dst *Message) XXX_Merge(src proto.Message) { + xxx_messageInfo_Message.Merge(dst, src) +} +func (m *Message) XXX_Size() int { + return xxx_messageInfo_Message.Size(m) +} +func (m *Message) XXX_DiscardUnknown() { + xxx_messageInfo_Message.DiscardUnknown(m) +} + +var xxx_messageInfo_Message proto.InternalMessageInfo + +func (m *Message) GetLength() uint32 { + if m != nil { + return m.Length + } + return 0 +} + +func (m *Message) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + +// A list of metadata pairs, used in the payload of client header, +// server header, and server trailer. +// Implementations may omit some entries to honor the header limits +// of GRPC_BINARY_LOG_CONFIG. +// +// Header keys added by gRPC are omitted. To be more specific, +// implementations will not log the following entries, and this is +// not to be treated as a truncation: +// - entries handled by grpc that are not user visible, such as those +// that begin with 'grpc-' (with exception of grpc-trace-bin) +// or keys like 'lb-token' +// - transport specific entries, including but not limited to: +// ':path', ':authority', 'content-encoding', 'user-agent', 'te', etc +// - entries added for call credentials +// +// Implementations must always log grpc-trace-bin if it is present. +// Practically speaking it will only be visible on server side because +// grpc-trace-bin is managed by low level client side mechanisms +// inaccessible from the application level. On server side, the +// header is just a normal metadata key. +// The pair will not count towards the size limit. +type Metadata struct { + Entry []*MetadataEntry `protobuf:"bytes,1,rep,name=entry,proto3" json:"entry,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Metadata) Reset() { *m = Metadata{} } +func (m *Metadata) String() string { return proto.CompactTextString(m) } +func (*Metadata) ProtoMessage() {} +func (*Metadata) Descriptor() ([]byte, []int) { + return fileDescriptor_binarylog_264c8c9c551ce911, []int{5} +} +func (m *Metadata) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Metadata.Unmarshal(m, b) +} +func (m *Metadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Metadata.Marshal(b, m, deterministic) +} +func (dst *Metadata) XXX_Merge(src proto.Message) { + xxx_messageInfo_Metadata.Merge(dst, src) +} +func (m *Metadata) XXX_Size() int { + return xxx_messageInfo_Metadata.Size(m) +} +func (m *Metadata) XXX_DiscardUnknown() { + xxx_messageInfo_Metadata.DiscardUnknown(m) +} + +var xxx_messageInfo_Metadata proto.InternalMessageInfo + +func (m *Metadata) GetEntry() []*MetadataEntry { + if m != nil { + return m.Entry + } + return nil +} + +// A metadata key value pair +type MetadataEntry struct { + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MetadataEntry) Reset() { *m = MetadataEntry{} } +func (m *MetadataEntry) String() string { return proto.CompactTextString(m) } +func (*MetadataEntry) ProtoMessage() {} +func (*MetadataEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_binarylog_264c8c9c551ce911, []int{6} +} +func (m *MetadataEntry) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MetadataEntry.Unmarshal(m, b) +} +func (m *MetadataEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MetadataEntry.Marshal(b, m, deterministic) +} +func (dst *MetadataEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_MetadataEntry.Merge(dst, src) +} +func (m *MetadataEntry) XXX_Size() int { + return xxx_messageInfo_MetadataEntry.Size(m) +} +func (m *MetadataEntry) XXX_DiscardUnknown() { + xxx_messageInfo_MetadataEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_MetadataEntry proto.InternalMessageInfo + +func (m *MetadataEntry) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +func (m *MetadataEntry) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +// Address information +type Address struct { + Type Address_Type `protobuf:"varint,1,opt,name=type,proto3,enum=grpc.binarylog.v1.Address_Type" json:"type,omitempty"` + Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` + // only for TYPE_IPV4 and TYPE_IPV6 + IpPort uint32 `protobuf:"varint,3,opt,name=ip_port,json=ipPort,proto3" json:"ip_port,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Address) Reset() { *m = Address{} } +func (m *Address) String() string { return proto.CompactTextString(m) } +func (*Address) ProtoMessage() {} +func (*Address) Descriptor() ([]byte, []int) { + return fileDescriptor_binarylog_264c8c9c551ce911, []int{7} +} +func (m *Address) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Address.Unmarshal(m, b) +} +func (m *Address) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Address.Marshal(b, m, deterministic) +} +func (dst *Address) XXX_Merge(src proto.Message) { + xxx_messageInfo_Address.Merge(dst, src) +} +func (m *Address) XXX_Size() int { + return xxx_messageInfo_Address.Size(m) +} +func (m *Address) XXX_DiscardUnknown() { + xxx_messageInfo_Address.DiscardUnknown(m) +} + +var xxx_messageInfo_Address proto.InternalMessageInfo + +func (m *Address) GetType() Address_Type { + if m != nil { + return m.Type + } + return Address_TYPE_UNKNOWN +} + +func (m *Address) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *Address) GetIpPort() uint32 { + if m != nil { + return m.IpPort + } + return 0 +} + +func init() { + proto.RegisterType((*GrpcLogEntry)(nil), "grpc.binarylog.v1.GrpcLogEntry") + proto.RegisterType((*ClientHeader)(nil), "grpc.binarylog.v1.ClientHeader") + proto.RegisterType((*ServerHeader)(nil), "grpc.binarylog.v1.ServerHeader") + proto.RegisterType((*Trailer)(nil), "grpc.binarylog.v1.Trailer") + proto.RegisterType((*Message)(nil), "grpc.binarylog.v1.Message") + proto.RegisterType((*Metadata)(nil), "grpc.binarylog.v1.Metadata") + proto.RegisterType((*MetadataEntry)(nil), "grpc.binarylog.v1.MetadataEntry") + proto.RegisterType((*Address)(nil), "grpc.binarylog.v1.Address") + proto.RegisterEnum("grpc.binarylog.v1.GrpcLogEntry_EventType", GrpcLogEntry_EventType_name, GrpcLogEntry_EventType_value) + proto.RegisterEnum("grpc.binarylog.v1.GrpcLogEntry_Logger", GrpcLogEntry_Logger_name, GrpcLogEntry_Logger_value) + proto.RegisterEnum("grpc.binarylog.v1.Address_Type", Address_Type_name, Address_Type_value) +} + +func init() { + proto.RegisterFile("grpc/binarylog/grpc_binarylog_v1/binarylog.proto", fileDescriptor_binarylog_264c8c9c551ce911) +} + +var fileDescriptor_binarylog_264c8c9c551ce911 = []byte{ + // 900 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0x51, 0x6f, 0xe3, 0x44, + 0x10, 0x3e, 0x37, 0x69, 0xdc, 0x4c, 0x92, 0xca, 0x5d, 0x95, 0x3b, 0x5f, 0x29, 0x34, 0xb2, 0x04, + 0x0a, 0x42, 0x72, 0xb9, 0x94, 0xeb, 0xf1, 0x02, 0x52, 0x92, 0xfa, 0xd2, 0x88, 0x5c, 0x1a, 0x6d, + 0x72, 0x3d, 0x40, 0x48, 0xd6, 0x36, 0x5e, 0x1c, 0x0b, 0xc7, 0x6b, 0xd6, 0x9b, 0xa0, 0xfc, 0x2c, + 0xde, 0x90, 0xee, 0x77, 0xf1, 0x8e, 0xbc, 0x6b, 0x27, 0xa6, 0x69, 0x0f, 0x09, 0xde, 0x3c, 0xdf, + 0x7c, 0xf3, 0xcd, 0xee, 0x78, 0x66, 0x16, 0xbe, 0xf2, 0x79, 0x3c, 0x3b, 0xbf, 0x0b, 0x22, 0xc2, + 0xd7, 0x21, 0xf3, 0xcf, 0x53, 0xd3, 0xdd, 0x98, 0xee, 0xea, 0xc5, 0xd6, 0x67, 0xc7, 0x9c, 0x09, + 0x86, 0x8e, 0x52, 0x8a, 0xbd, 0x45, 0x57, 0x2f, 0x4e, 0x3e, 0xf5, 0x19, 0xf3, 0x43, 0x7a, 0x2e, + 0x09, 0x77, 0xcb, 0x5f, 0xce, 0xbd, 0x25, 0x27, 0x22, 0x60, 0x91, 0x0a, 0x39, 0x39, 0xbb, 0xef, + 0x17, 0xc1, 0x82, 0x26, 0x82, 0x2c, 0x62, 0x45, 0xb0, 0xde, 0xeb, 0x50, 0xef, 0xf3, 0x78, 0x36, + 0x64, 0xbe, 0x13, 0x09, 0xbe, 0x46, 0xdf, 0x40, 0x75, 0xc3, 0x31, 0xb5, 0xa6, 0xd6, 0xaa, 0xb5, + 0x4f, 0x6c, 0xa5, 0x62, 0xe7, 0x2a, 0xf6, 0x34, 0x67, 0xe0, 0x2d, 0x19, 0x3d, 0x03, 0x7d, 0x46, + 0xc2, 0xd0, 0x0d, 0x3c, 0x73, 0xaf, 0xa9, 0xb5, 0xca, 0xb8, 0x92, 0x9a, 0x03, 0x0f, 0xbd, 0x84, + 0x67, 0x09, 0xfd, 0x6d, 0x49, 0xa3, 0x19, 0x75, 0x03, 0xcf, 0xfd, 0x3d, 0x10, 0xf3, 0x20, 0x72, + 0x53, 0xa7, 0x59, 0x92, 0xc4, 0xe3, 0xdc, 0x3d, 0xf0, 0xde, 0x49, 0x67, 0x8f, 0x84, 0x21, 0xfa, + 0x16, 0xca, 0x62, 0x1d, 0x53, 0xb3, 0xdc, 0xd4, 0x5a, 0x87, 0xed, 0x2f, 0xec, 0x9d, 0xdb, 0xdb, + 0xc5, 0x83, 0xdb, 0xce, 0x8a, 0x46, 0x62, 0xba, 0x8e, 0x29, 0x96, 0x61, 0xe8, 0x3b, 0xa8, 0x84, + 0xcc, 0xf7, 0x29, 0x37, 0xf7, 0xa5, 0xc0, 0xe7, 0xff, 0x26, 0x30, 0x94, 0x6c, 0x9c, 0x45, 0xa1, + 0xd7, 0xd0, 0x98, 0x85, 0x01, 0x8d, 0x84, 0x3b, 0xa7, 0xc4, 0xa3, 0xdc, 0xac, 0xc8, 0x62, 0x9c, + 0x3d, 0x20, 0xd3, 0x93, 0xbc, 0x6b, 0x49, 0xbb, 0x7e, 0x82, 0xeb, 0xb3, 0x82, 0x9d, 0xea, 0x24, + 0x94, 0xaf, 0x28, 0xcf, 0x75, 0xf4, 0x47, 0x75, 0x26, 0x92, 0xb7, 0xd5, 0x49, 0x0a, 0x36, 0xba, + 0x04, 0x7d, 0x41, 0x93, 0x84, 0xf8, 0xd4, 0x3c, 0xc8, 0x7f, 0xcb, 0x8e, 0xc2, 0x1b, 0xc5, 0xb8, + 0x7e, 0x82, 0x73, 0x72, 0x1a, 0x27, 0x38, 0x09, 0x42, 0xca, 0xcd, 0xea, 0xa3, 0x71, 0x53, 0xc5, + 0x48, 0xe3, 0x32, 0x32, 0xfa, 0x12, 0x8e, 0x62, 0xb2, 0x0e, 0x19, 0xf1, 0x5c, 0xc1, 0x97, 0xd1, + 0x8c, 0x08, 0xea, 0x99, 0xd0, 0xd4, 0x5a, 0x07, 0xd8, 0xc8, 0x1c, 0xd3, 0x1c, 0x47, 0x36, 0x94, + 0x63, 0x4a, 0xb9, 0x59, 0x7b, 0x34, 0x43, 0xc7, 0xf3, 0x38, 0x4d, 0x12, 0x2c, 0x79, 0xd6, 0x5f, + 0x1a, 0x54, 0x37, 0x3f, 0x0c, 0x3d, 0x05, 0xe4, 0xdc, 0x3a, 0xa3, 0xa9, 0x3b, 0xfd, 0x71, 0xec, + 0xb8, 0x6f, 0x47, 0xdf, 0x8f, 0x6e, 0xde, 0x8d, 0x8c, 0x27, 0xe8, 0x14, 0xcc, 0x02, 0xde, 0x1b, + 0x0e, 0xd2, 0xef, 0x6b, 0xa7, 0x73, 0xe5, 0x60, 0x43, 0xbb, 0xe7, 0x9d, 0x38, 0xf8, 0xd6, 0xc1, + 0xb9, 0x77, 0x0f, 0x7d, 0x02, 0xcf, 0x77, 0x63, 0xdf, 0x38, 0x93, 0x49, 0xa7, 0xef, 0x18, 0xa5, + 0x7b, 0xee, 0x2c, 0x38, 0x77, 0x97, 0x51, 0x13, 0x4e, 0x1f, 0xc8, 0xdc, 0x19, 0xbe, 0x76, 0x7b, + 0xc3, 0x9b, 0x89, 0x63, 0xec, 0x3f, 0x2c, 0x30, 0xc5, 0x9d, 0xc1, 0xd0, 0xc1, 0x46, 0x05, 0x7d, + 0x04, 0x47, 0x45, 0x81, 0xce, 0xa8, 0xe7, 0x0c, 0x0d, 0xdd, 0xea, 0x42, 0x45, 0xb5, 0x19, 0x42, + 0x70, 0x38, 0xbc, 0xe9, 0xf7, 0x1d, 0x5c, 0xb8, 0xef, 0x11, 0x34, 0x32, 0x4c, 0x65, 0x34, 0xb4, + 0x02, 0xa4, 0x52, 0x18, 0x7b, 0xdd, 0x2a, 0xe8, 0x59, 0xfd, 0xad, 0xf7, 0x1a, 0xd4, 0x8b, 0xcd, + 0x87, 0x5e, 0xc1, 0xc1, 0x82, 0x0a, 0xe2, 0x11, 0x41, 0xb2, 0xe1, 0xfd, 0xf8, 0xc1, 0x2e, 0x51, + 0x14, 0xbc, 0x21, 0xa3, 0x33, 0xa8, 0x2d, 0xa8, 0x98, 0x33, 0xcf, 0x8d, 0xc8, 0x82, 0xca, 0x01, + 0xae, 0x62, 0x50, 0xd0, 0x88, 0x2c, 0x28, 0x3a, 0x85, 0x2a, 0x59, 0x8a, 0x39, 0xe3, 0x81, 0x58, + 0xcb, 0xb1, 0xad, 0xe2, 0x2d, 0x80, 0x2e, 0x40, 0x4f, 0x17, 0x01, 0x5b, 0x0a, 0x39, 0xae, 0xb5, + 0xf6, 0xf3, 0x9d, 0x9d, 0x71, 0x95, 0x6d, 0x26, 0x9c, 0x33, 0xad, 0x3e, 0xd4, 0x8b, 0x1d, 0xff, + 0x9f, 0x0f, 0x6f, 0xfd, 0xa1, 0x81, 0x9e, 0x75, 0xf0, 0xff, 0xaa, 0x40, 0x22, 0x88, 0x58, 0x26, + 0xee, 0x8c, 0x79, 0xaa, 0x02, 0x0d, 0x0c, 0x0a, 0xea, 0x31, 0x8f, 0xa2, 0xcf, 0xe0, 0x30, 0x23, + 0xe4, 0x73, 0xa8, 0xca, 0xd0, 0x50, 0x68, 0x36, 0x7a, 0x05, 0x9a, 0x47, 0x05, 0x09, 0xc2, 0x44, + 0x56, 0xa4, 0x9e, 0xd3, 0xae, 0x14, 0x68, 0xbd, 0x04, 0x3d, 0x8f, 0x78, 0x0a, 0x95, 0x90, 0x46, + 0xbe, 0x98, 0xcb, 0x03, 0x37, 0x70, 0x66, 0x21, 0x04, 0x65, 0x79, 0x8d, 0x3d, 0x19, 0x2f, 0xbf, + 0xad, 0x2e, 0x1c, 0xe4, 0x67, 0x47, 0x97, 0xb0, 0x4f, 0xd3, 0xcd, 0x65, 0x6a, 0xcd, 0x52, 0xab, + 0xd6, 0x6e, 0x7e, 0xe0, 0x9e, 0x72, 0xc3, 0x61, 0x45, 0xb7, 0x5e, 0x41, 0xe3, 0x1f, 0x38, 0x32, + 0xa0, 0xf4, 0x2b, 0x5d, 0xcb, 0xec, 0x55, 0x9c, 0x7e, 0xa2, 0x63, 0xd8, 0x5f, 0x91, 0x70, 0x49, + 0xb3, 0xdc, 0xca, 0xb0, 0xfe, 0xd4, 0x40, 0xcf, 0xe6, 0x18, 0x5d, 0x64, 0xdb, 0x59, 0x93, 0xcb, + 0xf5, 0xec, 0xf1, 0x89, 0xb7, 0x0b, 0x3b, 0xd9, 0x04, 0x9d, 0x28, 0x34, 0xeb, 0xb0, 0xdc, 0x4c, + 0x1f, 0x8f, 0x20, 0x76, 0x63, 0xc6, 0x85, 0xac, 0x6a, 0x03, 0x57, 0x82, 0x78, 0xcc, 0xb8, 0xb0, + 0x1c, 0x28, 0xcb, 0x1d, 0x61, 0x40, 0xfd, 0xde, 0x76, 0x68, 0x40, 0x55, 0x22, 0x83, 0xf1, 0xed, + 0xd7, 0x86, 0x56, 0x34, 0x2f, 0x8d, 0xbd, 0x8d, 0xf9, 0x76, 0x34, 0xf8, 0xc1, 0x28, 0x75, 0x7f, + 0x86, 0xe3, 0x80, 0xed, 0x1e, 0xb2, 0x7b, 0xd8, 0x95, 0xd6, 0x90, 0xf9, 0xe3, 0xb4, 0x51, 0xc7, + 0xda, 0x4f, 0xed, 0xac, 0x71, 0x7d, 0x16, 0x92, 0xc8, 0xb7, 0x19, 0x57, 0x4f, 0xf3, 0x87, 0x5e, + 0xea, 0xbb, 0x8a, 0xec, 0xf2, 0x8b, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0xe7, 0xf6, 0x4b, 0x50, + 0xd4, 0x07, 0x00, 0x00, +} diff --git a/vendor/google.golang.org/grpc/call.go b/vendor/google.golang.org/grpc/call.go index f73b7d5528f54b5929406addd1b8988a9edc486e..100f05dc74213a2f59bf90da8b106fdeef0d6843 100644 --- a/vendor/google.golang.org/grpc/call.go +++ b/vendor/google.golang.org/grpc/call.go @@ -19,7 +19,7 @@ package grpc import ( - "golang.org/x/net/context" + "context" ) // Invoke sends the RPC request on the wire and returns after response is @@ -63,31 +63,12 @@ func Invoke(ctx context.Context, method string, args, reply interface{}, cc *Cli var unaryStreamDesc = &StreamDesc{ServerStreams: false, ClientStreams: false} func invoke(ctx context.Context, method string, req, reply interface{}, cc *ClientConn, opts ...CallOption) error { - // TODO: implement retries in clientStream and make this simply - // newClientStream, SendMsg, RecvMsg. - firstAttempt := true - for { - csInt, err := newClientStream(ctx, unaryStreamDesc, cc, method, opts...) - if err != nil { - return err - } - cs := csInt.(*clientStream) - if err := cs.SendMsg(req); err != nil { - if !cs.c.failFast && cs.attempt.s.Unprocessed() && firstAttempt { - // TODO: Add a field to header for grpc-transparent-retry-attempts - firstAttempt = false - continue - } - return err - } - if err := cs.RecvMsg(reply); err != nil { - if !cs.c.failFast && cs.attempt.s.Unprocessed() && firstAttempt { - // TODO: Add a field to header for grpc-transparent-retry-attempts - firstAttempt = false - continue - } - return err - } - return nil + cs, err := newClientStream(ctx, unaryStreamDesc, cc, method, opts...) + if err != nil { + return err } + if err := cs.SendMsg(req); err != nil { + return err + } + return cs.RecvMsg(reply) } diff --git a/vendor/google.golang.org/grpc/call_test.go b/vendor/google.golang.org/grpc/call_test.go index d57d01e4a2fee003aaaff50aaaf9cf5c66544a80..7800c5d849990b7a4a9f27e9bb8c1cfa67b7ce6e 100644 --- a/vendor/google.golang.org/grpc/call_test.go +++ b/vendor/google.golang.org/grpc/call_test.go @@ -19,6 +19,7 @@ package grpc import ( + "context" "fmt" "io" "math" @@ -29,11 +30,10 @@ import ( "testing" "time" - "golang.org/x/net/context" "google.golang.org/grpc/codes" "google.golang.org/grpc/internal/leakcheck" + "google.golang.org/grpc/internal/transport" "google.golang.org/grpc/status" - "google.golang.org/grpc/transport" ) var ( diff --git a/vendor/google.golang.org/grpc/channelz/grpc_channelz_v1/channelz.pb.go b/vendor/google.golang.org/grpc/channelz/grpc_channelz_v1/channelz.pb.go index 747b8f833f24e86f4bcf68bc39475a117f8efac8..fab354af6f11e0b651c15dd4233d4deec64b6cbc 100644 --- a/vendor/google.golang.org/grpc/channelz/grpc_channelz_v1/channelz.pb.go +++ b/vendor/google.golang.org/grpc/channelz/grpc_channelz_v1/channelz.pb.go @@ -59,7 +59,7 @@ func (x ChannelConnectivityState_State) String() string { return proto.EnumName(ChannelConnectivityState_State_name, int32(x)) } func (ChannelConnectivityState_State) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{2, 0} + return fileDescriptor_channelz_449295370a82a4c0, []int{2, 0} } // The supported severity levels of trace events. @@ -89,7 +89,7 @@ func (x ChannelTraceEvent_Severity) String() string { return proto.EnumName(ChannelTraceEvent_Severity_name, int32(x)) } func (ChannelTraceEvent_Severity) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{4, 0} + return fileDescriptor_channelz_449295370a82a4c0, []int{4, 0} } // Channel is a logical grouping of channels, subchannels, and sockets. @@ -118,7 +118,7 @@ func (m *Channel) Reset() { *m = Channel{} } func (m *Channel) String() string { return proto.CompactTextString(m) } func (*Channel) ProtoMessage() {} func (*Channel) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{0} + return fileDescriptor_channelz_449295370a82a4c0, []int{0} } func (m *Channel) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Channel.Unmarshal(m, b) @@ -200,7 +200,7 @@ func (m *Subchannel) Reset() { *m = Subchannel{} } func (m *Subchannel) String() string { return proto.CompactTextString(m) } func (*Subchannel) ProtoMessage() {} func (*Subchannel) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{1} + return fileDescriptor_channelz_449295370a82a4c0, []int{1} } func (m *Subchannel) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Subchannel.Unmarshal(m, b) @@ -268,7 +268,7 @@ func (m *ChannelConnectivityState) Reset() { *m = ChannelConnectivitySta func (m *ChannelConnectivityState) String() string { return proto.CompactTextString(m) } func (*ChannelConnectivityState) ProtoMessage() {} func (*ChannelConnectivityState) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{2} + return fileDescriptor_channelz_449295370a82a4c0, []int{2} } func (m *ChannelConnectivityState) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChannelConnectivityState.Unmarshal(m, b) @@ -321,7 +321,7 @@ func (m *ChannelData) Reset() { *m = ChannelData{} } func (m *ChannelData) String() string { return proto.CompactTextString(m) } func (*ChannelData) ProtoMessage() {} func (*ChannelData) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{3} + return fileDescriptor_channelz_449295370a82a4c0, []int{3} } func (m *ChannelData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChannelData.Unmarshal(m, b) @@ -417,7 +417,7 @@ func (m *ChannelTraceEvent) Reset() { *m = ChannelTraceEvent{} } func (m *ChannelTraceEvent) String() string { return proto.CompactTextString(m) } func (*ChannelTraceEvent) ProtoMessage() {} func (*ChannelTraceEvent) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{4} + return fileDescriptor_channelz_449295370a82a4c0, []int{4} } func (m *ChannelTraceEvent) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChannelTraceEvent.Unmarshal(m, b) @@ -437,27 +437,6 @@ func (m *ChannelTraceEvent) XXX_DiscardUnknown() { var xxx_messageInfo_ChannelTraceEvent proto.InternalMessageInfo -type isChannelTraceEvent_ChildRef interface { - isChannelTraceEvent_ChildRef() -} - -type ChannelTraceEvent_ChannelRef struct { - ChannelRef *ChannelRef `protobuf:"bytes,4,opt,name=channel_ref,json=channelRef,proto3,oneof"` -} -type ChannelTraceEvent_SubchannelRef struct { - SubchannelRef *SubchannelRef `protobuf:"bytes,5,opt,name=subchannel_ref,json=subchannelRef,proto3,oneof"` -} - -func (*ChannelTraceEvent_ChannelRef) isChannelTraceEvent_ChildRef() {} -func (*ChannelTraceEvent_SubchannelRef) isChannelTraceEvent_ChildRef() {} - -func (m *ChannelTraceEvent) GetChildRef() isChannelTraceEvent_ChildRef { - if m != nil { - return m.ChildRef - } - return nil -} - func (m *ChannelTraceEvent) GetDescription() string { if m != nil { return m.Description @@ -479,6 +458,29 @@ func (m *ChannelTraceEvent) GetTimestamp() *timestamp.Timestamp { return nil } +type isChannelTraceEvent_ChildRef interface { + isChannelTraceEvent_ChildRef() +} + +type ChannelTraceEvent_ChannelRef struct { + ChannelRef *ChannelRef `protobuf:"bytes,4,opt,name=channel_ref,json=channelRef,proto3,oneof"` +} + +type ChannelTraceEvent_SubchannelRef struct { + SubchannelRef *SubchannelRef `protobuf:"bytes,5,opt,name=subchannel_ref,json=subchannelRef,proto3,oneof"` +} + +func (*ChannelTraceEvent_ChannelRef) isChannelTraceEvent_ChildRef() {} + +func (*ChannelTraceEvent_SubchannelRef) isChannelTraceEvent_ChildRef() {} + +func (m *ChannelTraceEvent) GetChildRef() isChannelTraceEvent_ChildRef { + if m != nil { + return m.ChildRef + } + return nil +} + func (m *ChannelTraceEvent) GetChannelRef() *ChannelRef { if x, ok := m.GetChildRef().(*ChannelTraceEvent_ChannelRef); ok { return x.ChannelRef @@ -586,7 +588,7 @@ func (m *ChannelTrace) Reset() { *m = ChannelTrace{} } func (m *ChannelTrace) String() string { return proto.CompactTextString(m) } func (*ChannelTrace) ProtoMessage() {} func (*ChannelTrace) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{5} + return fileDescriptor_channelz_449295370a82a4c0, []int{5} } func (m *ChannelTrace) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChannelTrace.Unmarshal(m, b) @@ -642,7 +644,7 @@ func (m *ChannelRef) Reset() { *m = ChannelRef{} } func (m *ChannelRef) String() string { return proto.CompactTextString(m) } func (*ChannelRef) ProtoMessage() {} func (*ChannelRef) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{6} + return fileDescriptor_channelz_449295370a82a4c0, []int{6} } func (m *ChannelRef) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChannelRef.Unmarshal(m, b) @@ -691,7 +693,7 @@ func (m *SubchannelRef) Reset() { *m = SubchannelRef{} } func (m *SubchannelRef) String() string { return proto.CompactTextString(m) } func (*SubchannelRef) ProtoMessage() {} func (*SubchannelRef) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{7} + return fileDescriptor_channelz_449295370a82a4c0, []int{7} } func (m *SubchannelRef) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SubchannelRef.Unmarshal(m, b) @@ -727,6 +729,7 @@ func (m *SubchannelRef) GetName() string { // SocketRef is a reference to a Socket. type SocketRef struct { + // The globally unique id for this socket. Must be a positive number. SocketId int64 `protobuf:"varint,3,opt,name=socket_id,json=socketId,proto3" json:"socket_id,omitempty"` // An optional name associated with the socket. Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` @@ -739,7 +742,7 @@ func (m *SocketRef) Reset() { *m = SocketRef{} } func (m *SocketRef) String() string { return proto.CompactTextString(m) } func (*SocketRef) ProtoMessage() {} func (*SocketRef) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{8} + return fileDescriptor_channelz_449295370a82a4c0, []int{8} } func (m *SocketRef) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SocketRef.Unmarshal(m, b) @@ -788,7 +791,7 @@ func (m *ServerRef) Reset() { *m = ServerRef{} } func (m *ServerRef) String() string { return proto.CompactTextString(m) } func (*ServerRef) ProtoMessage() {} func (*ServerRef) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{9} + return fileDescriptor_channelz_449295370a82a4c0, []int{9} } func (m *ServerRef) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ServerRef.Unmarshal(m, b) @@ -841,7 +844,7 @@ func (m *Server) Reset() { *m = Server{} } func (m *Server) String() string { return proto.CompactTextString(m) } func (*Server) ProtoMessage() {} func (*Server) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{10} + return fileDescriptor_channelz_449295370a82a4c0, []int{10} } func (m *Server) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Server.Unmarshal(m, b) @@ -903,7 +906,7 @@ func (m *ServerData) Reset() { *m = ServerData{} } func (m *ServerData) String() string { return proto.CompactTextString(m) } func (*ServerData) ProtoMessage() {} func (*ServerData) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{11} + return fileDescriptor_channelz_449295370a82a4c0, []int{11} } func (m *ServerData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ServerData.Unmarshal(m, b) @@ -983,7 +986,7 @@ func (m *Socket) Reset() { *m = Socket{} } func (m *Socket) String() string { return proto.CompactTextString(m) } func (*Socket) ProtoMessage() {} func (*Socket) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{12} + return fileDescriptor_channelz_449295370a82a4c0, []int{12} } func (m *Socket) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Socket.Unmarshal(m, b) @@ -1084,7 +1087,8 @@ type SocketData struct { // This may be slightly out of date due to network latency. This does NOT // include stream level or TCP level flow control info. RemoteFlowControlWindow *wrappers.Int64Value `protobuf:"bytes,12,opt,name=remote_flow_control_window,json=remoteFlowControlWindow,proto3" json:"remote_flow_control_window,omitempty"` - // Socket options set on this socket. May be absent. + // Socket options set on this socket. May be absent if 'summary' is set + // on GetSocketRequest. Option []*SocketOption `protobuf:"bytes,13,rep,name=option,proto3" json:"option,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -1095,7 +1099,7 @@ func (m *SocketData) Reset() { *m = SocketData{} } func (m *SocketData) String() string { return proto.CompactTextString(m) } func (*SocketData) ProtoMessage() {} func (*SocketData) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{13} + return fileDescriptor_channelz_449295370a82a4c0, []int{13} } func (m *SocketData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SocketData.Unmarshal(m, b) @@ -1222,7 +1226,7 @@ func (m *Address) Reset() { *m = Address{} } func (m *Address) String() string { return proto.CompactTextString(m) } func (*Address) ProtoMessage() {} func (*Address) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{14} + return fileDescriptor_channelz_449295370a82a4c0, []int{14} } func (m *Address) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Address.Unmarshal(m, b) @@ -1249,15 +1253,19 @@ type isAddress_Address interface { type Address_TcpipAddress struct { TcpipAddress *Address_TcpIpAddress `protobuf:"bytes,1,opt,name=tcpip_address,json=tcpipAddress,proto3,oneof"` } + type Address_UdsAddress_ struct { UdsAddress *Address_UdsAddress `protobuf:"bytes,2,opt,name=uds_address,json=udsAddress,proto3,oneof"` } + type Address_OtherAddress_ struct { OtherAddress *Address_OtherAddress `protobuf:"bytes,3,opt,name=other_address,json=otherAddress,proto3,oneof"` } -func (*Address_TcpipAddress) isAddress_Address() {} -func (*Address_UdsAddress_) isAddress_Address() {} +func (*Address_TcpipAddress) isAddress_Address() {} + +func (*Address_UdsAddress_) isAddress_Address() {} + func (*Address_OtherAddress_) isAddress_Address() {} func (m *Address) GetAddress() isAddress_Address { @@ -1396,7 +1404,7 @@ func (m *Address_TcpIpAddress) Reset() { *m = Address_TcpIpAddress{} } func (m *Address_TcpIpAddress) String() string { return proto.CompactTextString(m) } func (*Address_TcpIpAddress) ProtoMessage() {} func (*Address_TcpIpAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{14, 0} + return fileDescriptor_channelz_449295370a82a4c0, []int{14, 0} } func (m *Address_TcpIpAddress) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Address_TcpIpAddress.Unmarshal(m, b) @@ -1442,7 +1450,7 @@ func (m *Address_UdsAddress) Reset() { *m = Address_UdsAddress{} } func (m *Address_UdsAddress) String() string { return proto.CompactTextString(m) } func (*Address_UdsAddress) ProtoMessage() {} func (*Address_UdsAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{14, 1} + return fileDescriptor_channelz_449295370a82a4c0, []int{14, 1} } func (m *Address_UdsAddress) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Address_UdsAddress.Unmarshal(m, b) @@ -1484,7 +1492,7 @@ func (m *Address_OtherAddress) Reset() { *m = Address_OtherAddress{} } func (m *Address_OtherAddress) String() string { return proto.CompactTextString(m) } func (*Address_OtherAddress) ProtoMessage() {} func (*Address_OtherAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{14, 2} + return fileDescriptor_channelz_449295370a82a4c0, []int{14, 2} } func (m *Address_OtherAddress) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Address_OtherAddress.Unmarshal(m, b) @@ -1533,7 +1541,7 @@ func (m *Security) Reset() { *m = Security{} } func (m *Security) String() string { return proto.CompactTextString(m) } func (*Security) ProtoMessage() {} func (*Security) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{15} + return fileDescriptor_channelz_449295370a82a4c0, []int{15} } func (m *Security) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Security.Unmarshal(m, b) @@ -1560,11 +1568,13 @@ type isSecurity_Model interface { type Security_Tls_ struct { Tls *Security_Tls `protobuf:"bytes,1,opt,name=tls,proto3,oneof"` } + type Security_Other struct { Other *Security_OtherSecurity `protobuf:"bytes,2,opt,name=other,proto3,oneof"` } -func (*Security_Tls_) isSecurity_Model() {} +func (*Security_Tls_) isSecurity_Model() {} + func (*Security_Other) isSecurity_Model() {} func (m *Security) GetModel() isSecurity_Model { @@ -1680,7 +1690,7 @@ func (m *Security_Tls) Reset() { *m = Security_Tls{} } func (m *Security_Tls) String() string { return proto.CompactTextString(m) } func (*Security_Tls) ProtoMessage() {} func (*Security_Tls) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{15, 0} + return fileDescriptor_channelz_449295370a82a4c0, []int{15, 0} } func (m *Security_Tls) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Security_Tls.Unmarshal(m, b) @@ -1707,12 +1717,14 @@ type isSecurity_Tls_CipherSuite interface { type Security_Tls_StandardName struct { StandardName string `protobuf:"bytes,1,opt,name=standard_name,json=standardName,proto3,oneof"` } + type Security_Tls_OtherName struct { OtherName string `protobuf:"bytes,2,opt,name=other_name,json=otherName,proto3,oneof"` } func (*Security_Tls_StandardName) isSecurity_Tls_CipherSuite() {} -func (*Security_Tls_OtherName) isSecurity_Tls_CipherSuite() {} + +func (*Security_Tls_OtherName) isSecurity_Tls_CipherSuite() {} func (m *Security_Tls) GetCipherSuite() isSecurity_Tls_CipherSuite { if m != nil { @@ -1829,7 +1841,7 @@ func (m *Security_OtherSecurity) Reset() { *m = Security_OtherSecurity{} func (m *Security_OtherSecurity) String() string { return proto.CompactTextString(m) } func (*Security_OtherSecurity) ProtoMessage() {} func (*Security_OtherSecurity) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{15, 1} + return fileDescriptor_channelz_449295370a82a4c0, []int{15, 1} } func (m *Security_OtherSecurity) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Security_OtherSecurity.Unmarshal(m, b) @@ -1884,7 +1896,7 @@ func (m *SocketOption) Reset() { *m = SocketOption{} } func (m *SocketOption) String() string { return proto.CompactTextString(m) } func (*SocketOption) ProtoMessage() {} func (*SocketOption) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{16} + return fileDescriptor_channelz_449295370a82a4c0, []int{16} } func (m *SocketOption) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SocketOption.Unmarshal(m, b) @@ -1938,7 +1950,7 @@ func (m *SocketOptionTimeout) Reset() { *m = SocketOptionTimeout{} } func (m *SocketOptionTimeout) String() string { return proto.CompactTextString(m) } func (*SocketOptionTimeout) ProtoMessage() {} func (*SocketOptionTimeout) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{17} + return fileDescriptor_channelz_449295370a82a4c0, []int{17} } func (m *SocketOptionTimeout) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SocketOptionTimeout.Unmarshal(m, b) @@ -1981,7 +1993,7 @@ func (m *SocketOptionLinger) Reset() { *m = SocketOptionLinger{} } func (m *SocketOptionLinger) String() string { return proto.CompactTextString(m) } func (*SocketOptionLinger) ProtoMessage() {} func (*SocketOptionLinger) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{18} + return fileDescriptor_channelz_449295370a82a4c0, []int{18} } func (m *SocketOptionLinger) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SocketOptionLinger.Unmarshal(m, b) @@ -2056,7 +2068,7 @@ func (m *SocketOptionTcpInfo) Reset() { *m = SocketOptionTcpInfo{} } func (m *SocketOptionTcpInfo) String() string { return proto.CompactTextString(m) } func (*SocketOptionTcpInfo) ProtoMessage() {} func (*SocketOptionTcpInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{19} + return fileDescriptor_channelz_449295370a82a4c0, []int{19} } func (m *SocketOptionTcpInfo) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SocketOptionTcpInfo.Unmarshal(m, b) @@ -2282,7 +2294,14 @@ func (m *SocketOptionTcpInfo) GetTcpiReordering() uint32 { type GetTopChannelsRequest struct { // start_channel_id indicates that only channels at or above this id should be // included in the results. - StartChannelId int64 `protobuf:"varint,1,opt,name=start_channel_id,json=startChannelId,proto3" json:"start_channel_id,omitempty"` + // To request the first page, this should be set to 0. To request + // subsequent pages, the client generates this value by adding 1 to + // the highest seen result ID. + StartChannelId int64 `protobuf:"varint,1,opt,name=start_channel_id,json=startChannelId,proto3" json:"start_channel_id,omitempty"` + // If non-zero, the server will return a page of results containing + // at most this many items. If zero, the server will choose a + // reasonable page size. Must never be negative. + MaxResults int64 `protobuf:"varint,2,opt,name=max_results,json=maxResults,proto3" json:"max_results,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -2292,7 +2311,7 @@ func (m *GetTopChannelsRequest) Reset() { *m = GetTopChannelsRequest{} } func (m *GetTopChannelsRequest) String() string { return proto.CompactTextString(m) } func (*GetTopChannelsRequest) ProtoMessage() {} func (*GetTopChannelsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{20} + return fileDescriptor_channelz_449295370a82a4c0, []int{20} } func (m *GetTopChannelsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetTopChannelsRequest.Unmarshal(m, b) @@ -2319,9 +2338,17 @@ func (m *GetTopChannelsRequest) GetStartChannelId() int64 { return 0 } +func (m *GetTopChannelsRequest) GetMaxResults() int64 { + if m != nil { + return m.MaxResults + } + return 0 +} + type GetTopChannelsResponse struct { // list of channels that the connection detail service knows about. Sorted in // ascending channel_id order. + // Must contain at least 1 result, otherwise 'end' must be true. Channel []*Channel `protobuf:"bytes,1,rep,name=channel,proto3" json:"channel,omitempty"` // If set, indicates that the list of channels is the final list. Requesting // more channels can only return more if they are created after this RPC @@ -2336,7 +2363,7 @@ func (m *GetTopChannelsResponse) Reset() { *m = GetTopChannelsResponse{} func (m *GetTopChannelsResponse) String() string { return proto.CompactTextString(m) } func (*GetTopChannelsResponse) ProtoMessage() {} func (*GetTopChannelsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{21} + return fileDescriptor_channelz_449295370a82a4c0, []int{21} } func (m *GetTopChannelsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetTopChannelsResponse.Unmarshal(m, b) @@ -2373,7 +2400,14 @@ func (m *GetTopChannelsResponse) GetEnd() bool { type GetServersRequest struct { // start_server_id indicates that only servers at or above this id should be // included in the results. - StartServerId int64 `protobuf:"varint,1,opt,name=start_server_id,json=startServerId,proto3" json:"start_server_id,omitempty"` + // To request the first page, this must be set to 0. To request + // subsequent pages, the client generates this value by adding 1 to + // the highest seen result ID. + StartServerId int64 `protobuf:"varint,1,opt,name=start_server_id,json=startServerId,proto3" json:"start_server_id,omitempty"` + // If non-zero, the server will return a page of results containing + // at most this many items. If zero, the server will choose a + // reasonable page size. Must never be negative. + MaxResults int64 `protobuf:"varint,2,opt,name=max_results,json=maxResults,proto3" json:"max_results,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -2383,7 +2417,7 @@ func (m *GetServersRequest) Reset() { *m = GetServersRequest{} } func (m *GetServersRequest) String() string { return proto.CompactTextString(m) } func (*GetServersRequest) ProtoMessage() {} func (*GetServersRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{22} + return fileDescriptor_channelz_449295370a82a4c0, []int{22} } func (m *GetServersRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetServersRequest.Unmarshal(m, b) @@ -2410,9 +2444,17 @@ func (m *GetServersRequest) GetStartServerId() int64 { return 0 } +func (m *GetServersRequest) GetMaxResults() int64 { + if m != nil { + return m.MaxResults + } + return 0 +} + type GetServersResponse struct { // list of servers that the connection detail service knows about. Sorted in // ascending server_id order. + // Must contain at least 1 result, otherwise 'end' must be true. Server []*Server `protobuf:"bytes,1,rep,name=server,proto3" json:"server,omitempty"` // If set, indicates that the list of servers is the final list. Requesting // more servers will only return more if they are created after this RPC @@ -2427,7 +2469,7 @@ func (m *GetServersResponse) Reset() { *m = GetServersResponse{} } func (m *GetServersResponse) String() string { return proto.CompactTextString(m) } func (*GetServersResponse) ProtoMessage() {} func (*GetServersResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{23} + return fileDescriptor_channelz_449295370a82a4c0, []int{23} } func (m *GetServersResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetServersResponse.Unmarshal(m, b) @@ -2461,11 +2503,97 @@ func (m *GetServersResponse) GetEnd() bool { return false } +type GetServerRequest struct { + // server_id is the identifier of the specific server to get. + ServerId int64 `protobuf:"varint,1,opt,name=server_id,json=serverId,proto3" json:"server_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetServerRequest) Reset() { *m = GetServerRequest{} } +func (m *GetServerRequest) String() string { return proto.CompactTextString(m) } +func (*GetServerRequest) ProtoMessage() {} +func (*GetServerRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_channelz_449295370a82a4c0, []int{24} +} +func (m *GetServerRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetServerRequest.Unmarshal(m, b) +} +func (m *GetServerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetServerRequest.Marshal(b, m, deterministic) +} +func (dst *GetServerRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetServerRequest.Merge(dst, src) +} +func (m *GetServerRequest) XXX_Size() int { + return xxx_messageInfo_GetServerRequest.Size(m) +} +func (m *GetServerRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetServerRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GetServerRequest proto.InternalMessageInfo + +func (m *GetServerRequest) GetServerId() int64 { + if m != nil { + return m.ServerId + } + return 0 +} + +type GetServerResponse struct { + // The Server that corresponds to the requested server_id. This field + // should be set. + Server *Server `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetServerResponse) Reset() { *m = GetServerResponse{} } +func (m *GetServerResponse) String() string { return proto.CompactTextString(m) } +func (*GetServerResponse) ProtoMessage() {} +func (*GetServerResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_channelz_449295370a82a4c0, []int{25} +} +func (m *GetServerResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetServerResponse.Unmarshal(m, b) +} +func (m *GetServerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetServerResponse.Marshal(b, m, deterministic) +} +func (dst *GetServerResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetServerResponse.Merge(dst, src) +} +func (m *GetServerResponse) XXX_Size() int { + return xxx_messageInfo_GetServerResponse.Size(m) +} +func (m *GetServerResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetServerResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GetServerResponse proto.InternalMessageInfo + +func (m *GetServerResponse) GetServer() *Server { + if m != nil { + return m.Server + } + return nil +} + type GetServerSocketsRequest struct { ServerId int64 `protobuf:"varint,1,opt,name=server_id,json=serverId,proto3" json:"server_id,omitempty"` // start_socket_id indicates that only sockets at or above this id should be // included in the results. - StartSocketId int64 `protobuf:"varint,2,opt,name=start_socket_id,json=startSocketId,proto3" json:"start_socket_id,omitempty"` + // To request the first page, this must be set to 0. To request + // subsequent pages, the client generates this value by adding 1 to + // the highest seen result ID. + StartSocketId int64 `protobuf:"varint,2,opt,name=start_socket_id,json=startSocketId,proto3" json:"start_socket_id,omitempty"` + // If non-zero, the server will return a page of results containing + // at most this many items. If zero, the server will choose a + // reasonable page size. Must never be negative. + MaxResults int64 `protobuf:"varint,3,opt,name=max_results,json=maxResults,proto3" json:"max_results,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -2475,7 +2603,7 @@ func (m *GetServerSocketsRequest) Reset() { *m = GetServerSocketsRequest func (m *GetServerSocketsRequest) String() string { return proto.CompactTextString(m) } func (*GetServerSocketsRequest) ProtoMessage() {} func (*GetServerSocketsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{24} + return fileDescriptor_channelz_449295370a82a4c0, []int{26} } func (m *GetServerSocketsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetServerSocketsRequest.Unmarshal(m, b) @@ -2509,9 +2637,17 @@ func (m *GetServerSocketsRequest) GetStartSocketId() int64 { return 0 } +func (m *GetServerSocketsRequest) GetMaxResults() int64 { + if m != nil { + return m.MaxResults + } + return 0 +} + type GetServerSocketsResponse struct { // list of socket refs that the connection detail service knows about. Sorted in // ascending socket_id order. + // Must contain at least 1 result, otherwise 'end' must be true. SocketRef []*SocketRef `protobuf:"bytes,1,rep,name=socket_ref,json=socketRef,proto3" json:"socket_ref,omitempty"` // If set, indicates that the list of sockets is the final list. Requesting // more sockets will only return more if they are created after this RPC @@ -2526,7 +2662,7 @@ func (m *GetServerSocketsResponse) Reset() { *m = GetServerSocketsRespon func (m *GetServerSocketsResponse) String() string { return proto.CompactTextString(m) } func (*GetServerSocketsResponse) ProtoMessage() {} func (*GetServerSocketsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{25} + return fileDescriptor_channelz_449295370a82a4c0, []int{27} } func (m *GetServerSocketsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetServerSocketsResponse.Unmarshal(m, b) @@ -2572,7 +2708,7 @@ func (m *GetChannelRequest) Reset() { *m = GetChannelRequest{} } func (m *GetChannelRequest) String() string { return proto.CompactTextString(m) } func (*GetChannelRequest) ProtoMessage() {} func (*GetChannelRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{26} + return fileDescriptor_channelz_449295370a82a4c0, []int{28} } func (m *GetChannelRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetChannelRequest.Unmarshal(m, b) @@ -2612,7 +2748,7 @@ func (m *GetChannelResponse) Reset() { *m = GetChannelResponse{} } func (m *GetChannelResponse) String() string { return proto.CompactTextString(m) } func (*GetChannelResponse) ProtoMessage() {} func (*GetChannelResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{27} + return fileDescriptor_channelz_449295370a82a4c0, []int{29} } func (m *GetChannelResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetChannelResponse.Unmarshal(m, b) @@ -2651,7 +2787,7 @@ func (m *GetSubchannelRequest) Reset() { *m = GetSubchannelRequest{} } func (m *GetSubchannelRequest) String() string { return proto.CompactTextString(m) } func (*GetSubchannelRequest) ProtoMessage() {} func (*GetSubchannelRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{28} + return fileDescriptor_channelz_449295370a82a4c0, []int{30} } func (m *GetSubchannelRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSubchannelRequest.Unmarshal(m, b) @@ -2691,7 +2827,7 @@ func (m *GetSubchannelResponse) Reset() { *m = GetSubchannelResponse{} } func (m *GetSubchannelResponse) String() string { return proto.CompactTextString(m) } func (*GetSubchannelResponse) ProtoMessage() {} func (*GetSubchannelResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{29} + return fileDescriptor_channelz_449295370a82a4c0, []int{31} } func (m *GetSubchannelResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSubchannelResponse.Unmarshal(m, b) @@ -2720,7 +2856,11 @@ func (m *GetSubchannelResponse) GetSubchannel() *Subchannel { type GetSocketRequest struct { // socket_id is the identifier of the specific socket to get. - SocketId int64 `protobuf:"varint,1,opt,name=socket_id,json=socketId,proto3" json:"socket_id,omitempty"` + SocketId int64 `protobuf:"varint,1,opt,name=socket_id,json=socketId,proto3" json:"socket_id,omitempty"` + // If true, the response will contain only high level information + // that is inexpensive to obtain. Fields thay may be omitted are + // documented. + Summary bool `protobuf:"varint,2,opt,name=summary,proto3" json:"summary,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -2730,7 +2870,7 @@ func (m *GetSocketRequest) Reset() { *m = GetSocketRequest{} } func (m *GetSocketRequest) String() string { return proto.CompactTextString(m) } func (*GetSocketRequest) ProtoMessage() {} func (*GetSocketRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{30} + return fileDescriptor_channelz_449295370a82a4c0, []int{32} } func (m *GetSocketRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSocketRequest.Unmarshal(m, b) @@ -2757,6 +2897,13 @@ func (m *GetSocketRequest) GetSocketId() int64 { return 0 } +func (m *GetSocketRequest) GetSummary() bool { + if m != nil { + return m.Summary + } + return false +} + type GetSocketResponse struct { // The Socket that corresponds to the requested socket_id. This field // should be set. @@ -2770,7 +2917,7 @@ func (m *GetSocketResponse) Reset() { *m = GetSocketResponse{} } func (m *GetSocketResponse) String() string { return proto.CompactTextString(m) } func (*GetSocketResponse) ProtoMessage() {} func (*GetSocketResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_channelz_ce3ed45d08251f2f, []int{31} + return fileDescriptor_channelz_449295370a82a4c0, []int{33} } func (m *GetSocketResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSocketResponse.Unmarshal(m, b) @@ -2827,6 +2974,8 @@ func init() { proto.RegisterType((*GetTopChannelsResponse)(nil), "grpc.channelz.v1.GetTopChannelsResponse") proto.RegisterType((*GetServersRequest)(nil), "grpc.channelz.v1.GetServersRequest") proto.RegisterType((*GetServersResponse)(nil), "grpc.channelz.v1.GetServersResponse") + proto.RegisterType((*GetServerRequest)(nil), "grpc.channelz.v1.GetServerRequest") + proto.RegisterType((*GetServerResponse)(nil), "grpc.channelz.v1.GetServerResponse") proto.RegisterType((*GetServerSocketsRequest)(nil), "grpc.channelz.v1.GetServerSocketsRequest") proto.RegisterType((*GetServerSocketsResponse)(nil), "grpc.channelz.v1.GetServerSocketsResponse") proto.RegisterType((*GetChannelRequest)(nil), "grpc.channelz.v1.GetChannelRequest") @@ -2856,6 +3005,8 @@ type ChannelzClient interface { GetTopChannels(ctx context.Context, in *GetTopChannelsRequest, opts ...grpc.CallOption) (*GetTopChannelsResponse, error) // Gets all servers that exist in the process. GetServers(ctx context.Context, in *GetServersRequest, opts ...grpc.CallOption) (*GetServersResponse, error) + // Returns a single Server, or else a NOT_FOUND code. + GetServer(ctx context.Context, in *GetServerRequest, opts ...grpc.CallOption) (*GetServerResponse, error) // Gets all server sockets that exist in the process. GetServerSockets(ctx context.Context, in *GetServerSocketsRequest, opts ...grpc.CallOption) (*GetServerSocketsResponse, error) // Returns a single Channel, or else a NOT_FOUND code. @@ -2892,6 +3043,15 @@ func (c *channelzClient) GetServers(ctx context.Context, in *GetServersRequest, return out, nil } +func (c *channelzClient) GetServer(ctx context.Context, in *GetServerRequest, opts ...grpc.CallOption) (*GetServerResponse, error) { + out := new(GetServerResponse) + err := c.cc.Invoke(ctx, "/grpc.channelz.v1.Channelz/GetServer", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *channelzClient) GetServerSockets(ctx context.Context, in *GetServerSocketsRequest, opts ...grpc.CallOption) (*GetServerSocketsResponse, error) { out := new(GetServerSocketsResponse) err := c.cc.Invoke(ctx, "/grpc.channelz.v1.Channelz/GetServerSockets", in, out, opts...) @@ -2935,6 +3095,8 @@ type ChannelzServer interface { GetTopChannels(context.Context, *GetTopChannelsRequest) (*GetTopChannelsResponse, error) // Gets all servers that exist in the process. GetServers(context.Context, *GetServersRequest) (*GetServersResponse, error) + // Returns a single Server, or else a NOT_FOUND code. + GetServer(context.Context, *GetServerRequest) (*GetServerResponse, error) // Gets all server sockets that exist in the process. GetServerSockets(context.Context, *GetServerSocketsRequest) (*GetServerSocketsResponse, error) // Returns a single Channel, or else a NOT_FOUND code. @@ -2985,6 +3147,24 @@ func _Channelz_GetServers_Handler(srv interface{}, ctx context.Context, dec func return interceptor(ctx, in, info, handler) } +func _Channelz_GetServer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetServerRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChannelzServer).GetServer(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.channelz.v1.Channelz/GetServer", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChannelzServer).GetServer(ctx, req.(*GetServerRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Channelz_GetServerSockets_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetServerSocketsRequest) if err := dec(in); err != nil { @@ -3069,6 +3249,10 @@ var _Channelz_serviceDesc = grpc.ServiceDesc{ MethodName: "GetServers", Handler: _Channelz_GetServers_Handler, }, + { + MethodName: "GetServer", + Handler: _Channelz_GetServer_Handler, + }, { MethodName: "GetServerSockets", Handler: _Channelz_GetServerSockets_Handler, @@ -3091,167 +3275,171 @@ var _Channelz_serviceDesc = grpc.ServiceDesc{ } func init() { - proto.RegisterFile("grpc/channelz/v1/channelz.proto", fileDescriptor_channelz_ce3ed45d08251f2f) -} - -var fileDescriptor_channelz_ce3ed45d08251f2f = []byte{ - // 2515 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x59, 0x4b, 0x6f, 0xdb, 0xca, - 0x15, 0xb6, 0xde, 0xd4, 0xd1, 0x23, 0xf2, 0xe4, 0x45, 0x2b, 0x0f, 0xbb, 0x74, 0x6e, 0xe2, 0x9b, - 0x34, 0x72, 0xec, 0x9b, 0x06, 0x45, 0xd3, 0xa2, 0x57, 0x56, 0xec, 0x58, 0xae, 0x23, 0x07, 0x94, - 0x7c, 0x93, 0xdb, 0xc5, 0xe5, 0x65, 0xc8, 0xb1, 0xcc, 0x9a, 0x22, 0x55, 0xce, 0x48, 0x46, 0xb2, - 0xed, 0xbe, 0xcb, 0xa2, 0xbf, 0xa0, 0x9b, 0x2e, 0x0a, 0x14, 0x28, 0xd0, 0x6e, 0x8b, 0xfe, 0x99, - 0xfe, 0x8b, 0x62, 0x1e, 0x7c, 0xc8, 0x92, 0x2c, 0x07, 0x59, 0x76, 0x63, 0x88, 0x87, 0xdf, 0xf9, - 0xce, 0x99, 0xf3, 0x9a, 0xe1, 0x18, 0x56, 0xfb, 0xc1, 0xd0, 0xda, 0xb4, 0x4e, 0x4d, 0xcf, 0xc3, - 0xee, 0xa7, 0xcd, 0xf1, 0x56, 0xf4, 0xbb, 0x31, 0x0c, 0x7c, 0xea, 0xa3, 0x1a, 0x03, 0x34, 0x22, - 0xe1, 0x78, 0xab, 0xbe, 0xd2, 0xf7, 0xfd, 0xbe, 0x8b, 0x37, 0xf9, 0xfb, 0x0f, 0xa3, 0x93, 0x4d, - 0xd3, 0xfb, 0x28, 0xc0, 0xf5, 0xfb, 0x17, 0x5f, 0xd9, 0xa3, 0xc0, 0xa4, 0x8e, 0xef, 0xc9, 0xf7, - 0xab, 0x17, 0xdf, 0x53, 0x67, 0x80, 0x09, 0x35, 0x07, 0xc3, 0x79, 0x04, 0xe7, 0x81, 0x39, 0x1c, - 0xe2, 0x80, 0x88, 0xf7, 0xda, 0xdf, 0xd2, 0x50, 0x68, 0x09, 0x5f, 0x50, 0x03, 0x32, 0x01, 0x3e, - 0x51, 0x53, 0x6b, 0xa9, 0x8d, 0xd2, 0xf6, 0xdd, 0xc6, 0x45, 0x3f, 0x1b, 0x12, 0xa7, 0xe3, 0x13, - 0x9d, 0x01, 0xd1, 0x16, 0x64, 0x6d, 0x93, 0x9a, 0x6a, 0x9a, 0x2b, 0xdc, 0x9b, 0xab, 0xf0, 0xca, - 0xa4, 0xa6, 0xce, 0xa1, 0xe8, 0x57, 0x50, 0x92, 0x00, 0x83, 0x99, 0xca, 0xac, 0x65, 0x16, 0x9a, - 0x02, 0x2b, 0xfa, 0x8d, 0xf6, 0xa0, 0x4a, 0x46, 0x1f, 0x92, 0x0c, 0x59, 0xce, 0xb0, 0x3a, 0xcd, - 0xd0, 0x8d, 0x70, 0x8c, 0xa4, 0x42, 0x92, 0x8f, 0xe8, 0x17, 0x00, 0xc4, 0xb7, 0xce, 0x30, 0xe5, - 0x1c, 0x39, 0xce, 0x71, 0x67, 0x06, 0x07, 0xc7, 0x30, 0xfd, 0x22, 0x09, 0x7f, 0x6a, 0xff, 0x48, - 0x03, 0xc4, 0xe4, 0x68, 0x2b, 0x19, 0xb4, 0x85, 0x7e, 0xfc, 0x1f, 0xc7, 0xed, 0xdf, 0x29, 0x50, - 0xa5, 0x7b, 0x2d, 0xdf, 0xf3, 0xb0, 0x45, 0x9d, 0xb1, 0x43, 0x3f, 0x76, 0xa9, 0x49, 0x31, 0xda, - 0x83, 0x1c, 0x61, 0x3f, 0x78, 0x1c, 0xab, 0xdb, 0xcf, 0xe6, 0xae, 0x6c, 0x4a, 0xb5, 0xc1, 0xff, - 0xea, 0x42, 0x5d, 0xfb, 0x01, 0x72, 0x82, 0xb0, 0x04, 0x85, 0xe3, 0xce, 0x6f, 0x3a, 0x47, 0xef, - 0x3a, 0xb5, 0x25, 0xa4, 0x40, 0xb6, 0xfd, 0xea, 0x70, 0xb7, 0x96, 0x42, 0x55, 0x80, 0xd6, 0x51, - 0xa7, 0xb3, 0xdb, 0xea, 0xb5, 0x3b, 0xaf, 0x6b, 0x69, 0x54, 0x84, 0x9c, 0xbe, 0xdb, 0x7c, 0xf5, - 0x7d, 0x2d, 0x83, 0x6e, 0xc2, 0x72, 0x4f, 0x6f, 0x76, 0xba, 0xed, 0xdd, 0x4e, 0xcf, 0xd8, 0x6b, - 0xb6, 0x0f, 0x8f, 0xf5, 0xdd, 0x5a, 0x16, 0x95, 0x41, 0xe9, 0xee, 0x1f, 0xf7, 0x5e, 0x31, 0xa6, - 0x9c, 0xf6, 0xdf, 0x34, 0x94, 0x12, 0xd9, 0x41, 0xdf, 0x26, 0xfd, 0x2e, 0x6d, 0x3f, 0xbe, 0xba, - 0xdf, 0xd2, 0x63, 0x74, 0x0b, 0xf2, 0xd4, 0x0c, 0xfa, 0x98, 0xf2, 0x72, 0x28, 0xea, 0xf2, 0x09, - 0x3d, 0x87, 0x1c, 0x0d, 0x4c, 0x0b, 0xab, 0x19, 0xce, 0x7c, 0x7f, 0x2e, 0x73, 0x8f, 0xa1, 0x74, - 0x01, 0x46, 0xeb, 0x50, 0xb1, 0x4c, 0xd7, 0x25, 0x06, 0xa1, 0x66, 0x40, 0xb1, 0xad, 0x66, 0xd7, - 0x52, 0x1b, 0x19, 0xbd, 0xcc, 0x85, 0x5d, 0x21, 0x43, 0x8f, 0xe0, 0x9a, 0x04, 0x8d, 0x2c, 0x0b, - 0x63, 0x1b, 0xdb, 0x6a, 0x8e, 0xc3, 0xaa, 0x02, 0x16, 0x4a, 0xd1, 0x4f, 0x40, 0x28, 0x1a, 0x27, - 0xa6, 0xe3, 0x62, 0x5b, 0xcd, 0x73, 0x54, 0x89, 0xcb, 0xf6, 0xb8, 0x08, 0x7d, 0x0f, 0x77, 0x5c, - 0x93, 0x50, 0x83, 0xc9, 0x42, 0xa3, 0x46, 0x34, 0x84, 0xd4, 0x02, 0x77, 0xbe, 0xde, 0x10, 0x53, - 0xa8, 0x11, 0x4e, 0xa1, 0x46, 0x2f, 0x44, 0xe8, 0x2a, 0x53, 0x6f, 0x99, 0xae, 0x2b, 0xbd, 0x8b, - 0xde, 0x68, 0x7f, 0xce, 0xc0, 0x72, 0x72, 0x8d, 0xbb, 0x63, 0xec, 0x51, 0xb4, 0x06, 0x25, 0x1b, - 0x13, 0x2b, 0x70, 0x86, 0x6c, 0x0c, 0xf2, 0xb8, 0x17, 0xf5, 0xa4, 0x08, 0xed, 0x83, 0x42, 0xf0, - 0x18, 0x07, 0x0e, 0xfd, 0xc8, 0x63, 0x5a, 0xdd, 0xfe, 0xe9, 0xe5, 0xc1, 0xe3, 0xc4, 0x8d, 0xae, - 0xd4, 0xd1, 0x23, 0x6d, 0xf4, 0x73, 0x28, 0xc6, 0x4b, 0xc9, 0x2c, 0x5c, 0x4a, 0x0c, 0x46, 0xbf, - 0x9e, 0xec, 0xd7, 0xec, 0xe2, 0x91, 0xba, 0xbf, 0x34, 0xd1, 0xb1, 0xfb, 0x53, 0x1d, 0x9b, 0xbb, - 0xd2, 0x84, 0xd9, 0x5f, 0xba, 0xd0, 0xb3, 0xda, 0x2e, 0x28, 0xe1, 0xd2, 0x78, 0xf9, 0xf7, 0x8c, - 0xb8, 0x31, 0x4a, 0x50, 0x68, 0xf5, 0x8c, 0x76, 0x67, 0xef, 0x48, 0xf6, 0x46, 0xcf, 0x78, 0xd7, - 0xd4, 0x3b, 0xa2, 0x37, 0xca, 0xa0, 0xb4, 0x7a, 0xc6, 0xae, 0xae, 0x1f, 0xe9, 0xb5, 0xcc, 0x4e, - 0x09, 0x8a, 0xd6, 0xa9, 0xe3, 0xda, 0xcc, 0x17, 0xd6, 0xcb, 0xe5, 0x64, 0x04, 0xd1, 0x63, 0x58, - 0xf6, 0x46, 0x03, 0x03, 0xb3, 0x48, 0x12, 0xc3, 0xf5, 0xfb, 0x7d, 0x6c, 0xf3, 0xdc, 0x64, 0xf4, - 0x6b, 0xde, 0x68, 0xc0, 0x23, 0x4c, 0x0e, 0xb9, 0x18, 0xb5, 0x01, 0x59, 0x01, 0xe6, 0xbb, 0x58, - 0xa2, 0x52, 0xd2, 0x0b, 0xc3, 0xbb, 0x1c, 0x6a, 0x45, 0x22, 0xf4, 0x12, 0xf2, 0xc2, 0xa4, 0x9c, - 0x88, 0xeb, 0x57, 0x48, 0xb4, 0x2e, 0x55, 0x34, 0x0b, 0x20, 0x0e, 0x3f, 0xba, 0x07, 0x61, 0xf8, - 0x0d, 0x27, 0x74, 0xbd, 0x28, 0x25, 0x6d, 0x1b, 0x21, 0xc8, 0x7a, 0xe6, 0x00, 0xcb, 0x26, 0xe5, - 0xbf, 0x0f, 0xb2, 0x4a, 0xa6, 0x96, 0x3d, 0xc8, 0x2a, 0xd9, 0x5a, 0xee, 0x20, 0xab, 0xe4, 0x6a, - 0xf9, 0x83, 0xac, 0x92, 0xaf, 0x15, 0x0e, 0xb2, 0x4a, 0xa1, 0xa6, 0x1c, 0x64, 0x15, 0xa5, 0x56, - 0xd4, 0x5c, 0xa8, 0x4c, 0xe4, 0x87, 0x75, 0x68, 0x22, 0xb1, 0x8e, 0xcd, 0x5b, 0x24, 0xa3, 0x97, - 0x63, 0x61, 0xc2, 0x9a, 0x32, 0x61, 0x2d, 0x55, 0x4b, 0x1f, 0x64, 0x95, 0x74, 0x2d, 0x33, 0xcf, - 0xb2, 0xf6, 0x23, 0x14, 0xa3, 0xd9, 0x8b, 0xee, 0x80, 0x9c, 0xbe, 0xcc, 0x4a, 0x86, 0x5b, 0x51, - 0x84, 0x20, 0x61, 0x21, 0x3b, 0xd7, 0xc2, 0xec, 0xf5, 0x30, 0x0b, 0x38, 0x18, 0xe3, 0x20, 0xb4, - 0xc0, 0x1f, 0x98, 0x85, 0x9c, 0xb4, 0xc0, 0x05, 0x09, 0x0b, 0xf9, 0x2b, 0xad, 0x21, 0xb6, 0xf0, - 0xd7, 0x14, 0xe4, 0x85, 0x09, 0xf4, 0x34, 0xb9, 0xb7, 0xce, 0xda, 0x67, 0x42, 0x4f, 0xc4, 0xbe, - 0xfa, 0x6c, 0x62, 0x5f, 0xbd, 0x3b, 0x0f, 0x9f, 0xd8, 0x56, 0xbf, 0x85, 0x8a, 0xeb, 0x10, 0x8a, - 0x3d, 0x43, 0x04, 0x46, 0x96, 0xd1, 0xa5, 0x5b, 0x5a, 0x59, 0x68, 0x08, 0x81, 0xf6, 0x47, 0x76, - 0x1a, 0x88, 0x68, 0xe3, 0xa9, 0x9d, 0xfa, 0xa2, 0xa9, 0x9d, 0xbe, 0xda, 0xd4, 0xce, 0x5c, 0x69, - 0x6a, 0x67, 0x3f, 0x7b, 0x6a, 0xe7, 0xbe, 0x60, 0x6a, 0xff, 0x25, 0x0d, 0x79, 0x11, 0x9b, 0xc5, - 0xe9, 0x8b, 0x62, 0x7a, 0xc5, 0xf4, 0x71, 0x7c, 0x22, 0x7d, 0x9b, 0x90, 0x73, 0x7d, 0xcb, 0x74, - 0xe5, 0x6c, 0x5e, 0x99, 0x56, 0x69, 0xda, 0x76, 0x80, 0x09, 0xd1, 0x05, 0x0e, 0x6d, 0x41, 0x3e, - 0xc0, 0x03, 0x9f, 0x62, 0x39, 0x91, 0x2f, 0xd1, 0x90, 0x40, 0xf4, 0x82, 0xed, 0x26, 0xd6, 0x88, - 0xef, 0x26, 0x51, 0x5c, 0xa6, 0x0b, 0x4b, 0x20, 0xf4, 0x08, 0x8b, 0x56, 0xa1, 0x24, 0x18, 0x8c, - 0x44, 0x17, 0x80, 0x10, 0x75, 0xcc, 0x01, 0xd6, 0xfe, 0x50, 0x00, 0x88, 0x57, 0xc4, 0xd2, 0x4b, - 0x68, 0x80, 0xcd, 0x41, 0x5c, 0x05, 0x62, 0x08, 0x55, 0xa5, 0x38, 0xac, 0x83, 0x27, 0xb0, 0x1c, - 0x01, 0xa3, 0x4a, 0x10, 0x05, 0x53, 0x0b, 0xa1, 0x51, 0x2d, 0x7c, 0x05, 0xa1, 0x7a, 0x58, 0x0d, - 0xa2, 0x66, 0x2a, 0x52, 0x2a, 0xeb, 0x61, 0x1d, 0x2a, 0x03, 0x4c, 0x88, 0xd9, 0xc7, 0xc4, 0x20, - 0xd8, 0xa3, 0xe1, 0xb1, 0x21, 0x14, 0x76, 0xd9, 0xce, 0xfb, 0x04, 0x96, 0x23, 0x50, 0x80, 0x2d, - 0xec, 0x8c, 0xa3, 0x83, 0x43, 0x2d, 0x7c, 0xa1, 0x4b, 0x39, 0xda, 0x80, 0xda, 0x19, 0xc6, 0x43, - 0xc3, 0x74, 0x9d, 0x71, 0x48, 0x2a, 0x8e, 0x0f, 0x55, 0x26, 0x6f, 0x72, 0x31, 0xa7, 0x3d, 0x85, - 0x75, 0x5e, 0x8b, 0x3c, 0x43, 0x86, 0xf0, 0xcb, 0xe0, 0xa3, 0xfe, 0x33, 0x4f, 0x12, 0xab, 0x8c, - 0xe6, 0x90, 0xb1, 0x74, 0x39, 0x49, 0x4b, 0x70, 0xc4, 0xbb, 0xc5, 0xef, 0xe0, 0x01, 0xb7, 0x24, - 0xf3, 0x32, 0xd7, 0x94, 0xb2, 0xd0, 0xd4, 0x1a, 0xe3, 0xd1, 0x39, 0xcd, 0x1c, 0x5b, 0x61, 0x87, - 0xc9, 0xc0, 0xf0, 0x00, 0x24, 0x4c, 0x14, 0xaf, 0xd6, 0x61, 0x6f, 0x84, 0x36, 0x8b, 0x53, 0x4c, - 0x6d, 0xc2, 0xea, 0x04, 0x75, 0x98, 0x8b, 0x04, 0x3d, 0x2c, 0xa4, 0xbf, 0x9b, 0xa0, 0x0f, 0x93, - 0x16, 0x9b, 0xf8, 0x0e, 0x56, 0x44, 0x3a, 0x4e, 0x5c, 0xff, 0xdc, 0xb0, 0x7c, 0x8f, 0x06, 0xbe, - 0x6b, 0x9c, 0x3b, 0x9e, 0xed, 0x9f, 0xab, 0xa5, 0xb0, 0x9f, 0x2f, 0x90, 0xb7, 0x3d, 0xfa, 0xe2, - 0xf9, 0x77, 0xa6, 0x3b, 0xc2, 0xfa, 0x2d, 0xae, 0xbd, 0xe7, 0xfa, 0xe7, 0x2d, 0xa1, 0xfb, 0x8e, - 0xab, 0xa2, 0xf7, 0x50, 0x97, 0xc1, 0x9f, 0x45, 0x5c, 0x5e, 0x4c, 0x7c, 0x5b, 0xa8, 0x4f, 0x33, - 0xbf, 0x80, 0xbc, 0x2f, 0x4e, 0x84, 0x15, 0x3e, 0xc2, 0xef, 0xcf, 0x1b, 0x1f, 0x47, 0x1c, 0xa5, - 0x4b, 0xb4, 0xf6, 0xcf, 0x0c, 0x14, 0x64, 0xcb, 0xa3, 0x37, 0x50, 0xa1, 0xd6, 0xd0, 0x19, 0x1a, - 0xa6, 0x10, 0xc8, 0xc9, 0xf5, 0x70, 0xee, 0x90, 0x68, 0xf4, 0xac, 0x61, 0x7b, 0x28, 0x1f, 0xf6, - 0x97, 0xf4, 0x32, 0x57, 0x0f, 0xe9, 0x5e, 0x43, 0x69, 0x64, 0x93, 0x88, 0x4c, 0x8c, 0xb5, 0x07, - 0xf3, 0xc9, 0x8e, 0x6d, 0x12, 0x53, 0xc1, 0x28, 0x7a, 0x62, 0x7e, 0xf9, 0xf4, 0x14, 0x07, 0x11, - 0x55, 0x66, 0x91, 0x5f, 0x47, 0x0c, 0x9e, 0xf0, 0xcb, 0x4f, 0x3c, 0xd7, 0x9b, 0x50, 0x4e, 0xfa, - 0xcd, 0x4e, 0x3e, 0x17, 0xd6, 0x5c, 0xd6, 0x8b, 0xf1, 0x32, 0x10, 0x64, 0x87, 0x7e, 0x20, 0x3e, - 0x4f, 0x72, 0x3a, 0xff, 0x5d, 0xdf, 0x00, 0x88, 0xbd, 0x45, 0x75, 0x50, 0x4e, 0x1c, 0x17, 0xf3, - 0x39, 0x27, 0xce, 0xe3, 0xd1, 0x73, 0xbd, 0x03, 0xe5, 0xa4, 0x33, 0xd1, 0xa9, 0x20, 0x15, 0x9f, - 0x0a, 0xd0, 0x63, 0xc8, 0x8d, 0x59, 0x76, 0x65, 0x88, 0x6e, 0x4c, 0x15, 0x40, 0xd3, 0xfb, 0xa8, - 0x0b, 0xc8, 0x4e, 0x11, 0x0a, 0xd2, 0x53, 0xed, 0x4f, 0x19, 0x76, 0xb2, 0x95, 0xe3, 0x76, 0x1b, - 0x32, 0xd4, 0x25, 0xf3, 0xb7, 0xdd, 0x10, 0xd8, 0xe8, 0xb9, 0x2c, 0x22, 0x0c, 0xcc, 0x3e, 0xde, - 0x78, 0x60, 0xa4, 0xdd, 0x8d, 0x4b, 0xb4, 0xf8, 0x1a, 0xc2, 0xa7, 0xfd, 0x25, 0x5d, 0x28, 0xd6, - 0xff, 0x95, 0x82, 0x4c, 0xcf, 0x25, 0xe8, 0x2b, 0xa8, 0x10, 0x6a, 0x7a, 0xb6, 0x19, 0xd8, 0x46, - 0xbc, 0x3c, 0x16, 0xf9, 0x50, 0xcc, 0x46, 0x3e, 0x5a, 0x05, 0x10, 0x89, 0x8c, 0x8f, 0x92, 0xfb, - 0x4b, 0x7a, 0x91, 0xcb, 0x38, 0xe0, 0x09, 0x2c, 0x8b, 0xbe, 0xb3, 0x70, 0x40, 0x9d, 0x13, 0xc7, - 0x62, 0x9f, 0x96, 0x19, 0x9e, 0x91, 0x1a, 0x7f, 0xd1, 0x8a, 0xe5, 0xe8, 0x29, 0x20, 0xd9, 0x4c, - 0x49, 0x74, 0x96, 0xa3, 0x97, 0xc5, 0x9b, 0x04, 0x7c, 0xa7, 0x0a, 0x65, 0xcb, 0x19, 0x32, 0xeb, - 0x64, 0xe4, 0x50, 0x5c, 0x3f, 0x82, 0xca, 0xc4, 0xaa, 0xbe, 0x38, 0x35, 0x05, 0xc8, 0x0d, 0x7c, - 0x1b, 0xbb, 0x9a, 0x07, 0xe5, 0x64, 0xaf, 0xcd, 0x24, 0xbe, 0x91, 0x24, 0x2e, 0x4a, 0x0a, 0xf4, - 0x1c, 0xc0, 0xb4, 0x6d, 0x87, 0x69, 0x45, 0xbb, 0xfa, 0x6c, 0x9b, 0x09, 0x9c, 0x76, 0x08, 0xd7, - 0x93, 0xf6, 0xd8, 0x18, 0xf3, 0x47, 0x14, 0xfd, 0x0c, 0x94, 0xf0, 0xb6, 0x4c, 0xd6, 0xc5, 0xca, - 0x14, 0xd5, 0x2b, 0x09, 0xd0, 0x23, 0xa8, 0x66, 0x01, 0x4a, 0xb2, 0x1d, 0x3a, 0x5e, 0x1f, 0x07, - 0xec, 0x33, 0xdd, 0x64, 0x9f, 0xef, 0x62, 0x15, 0x8a, 0x2e, 0x9f, 0x26, 0x8c, 0xa4, 0xaf, 0x6e, - 0xe4, 0xef, 0xca, 0x05, 0x9f, 0xad, 0x61, 0xdb, 0x3b, 0xf1, 0x59, 0x2f, 0xb2, 0x19, 0x62, 0xc4, - 0x97, 0x0a, 0x15, 0xbd, 0xc8, 0x24, 0xe2, 0x56, 0x43, 0x13, 0x13, 0xca, 0xb0, 0x4c, 0x89, 0x48, - 0x73, 0x44, 0x89, 0x09, 0x5b, 0xa6, 0xc0, 0x7c, 0x0d, 0x35, 0x8e, 0x09, 0x30, 0x0d, 0x4c, 0x8f, - 0x0c, 0x1c, 0x2a, 0x06, 0x46, 0x45, 0xbf, 0xc6, 0xe4, 0x7a, 0x2c, 0x66, 0x67, 0x14, 0x0e, 0x1d, - 0x06, 0xfe, 0x07, 0x4c, 0x78, 0xe9, 0x54, 0x74, 0xee, 0xc0, 0x5b, 0x2e, 0x61, 0x47, 0x49, 0x0e, - 0xf8, 0x60, 0x5a, 0x67, 0xfe, 0x89, 0xf8, 0x06, 0x95, 0xe6, 0x76, 0x84, 0x28, 0x82, 0x88, 0x79, - 0x4a, 0xf8, 0x26, 0x2f, 0x21, 0x62, 0x69, 0x04, 0x3d, 0x84, 0x6b, 0x62, 0x51, 0x9e, 0x6d, 0x9c, - 0x13, 0xcb, 0x74, 0x31, 0xdf, 0xcd, 0x2b, 0x3a, 0x5f, 0x4c, 0xd7, 0xb3, 0xdf, 0x71, 0x61, 0x84, - 0x0b, 0xac, 0x71, 0x88, 0x53, 0x62, 0x9c, 0x6e, 0x8d, 0x25, 0x6e, 0x05, 0x14, 0x81, 0xa3, 0x3e, - 0xdf, 0x48, 0x2b, 0x7a, 0x81, 0x03, 0xa8, 0x1f, 0xbd, 0x32, 0xa9, 0xcf, 0x37, 0x41, 0xf9, 0xaa, - 0x49, 0x7d, 0xb4, 0x26, 0x1d, 0x65, 0x5e, 0x0c, 0x08, 0xe1, 0xdb, 0x98, 0x5c, 0x6d, 0xd7, 0xb3, - 0xdf, 0x10, 0x12, 0x21, 0x98, 0x7d, 0x86, 0x28, 0xc7, 0x08, 0xdd, 0x1a, 0x33, 0x44, 0xb8, 0xd8, - 0x91, 0x67, 0x5a, 0x67, 0xd8, 0x56, 0x2b, 0xf1, 0x62, 0x8f, 0x85, 0x28, 0x8a, 0x29, 0x11, 0x88, - 0x6a, 0xc2, 0x8a, 0x00, 0xdc, 0x01, 0x9e, 0x50, 0xc3, 0xf5, 0x09, 0x55, 0xaf, 0xf1, 0xd7, 0xdc, - 0xe7, 0x43, 0x9f, 0xd0, 0xc8, 0x80, 0x4c, 0x9e, 0x5a, 0x8b, 0x0d, 0xc8, 0xc4, 0x45, 0x90, 0x13, - 0x46, 0x47, 0x89, 0xba, 0x1c, 0x43, 0xf6, 0x84, 0x08, 0x3d, 0x85, 0xeb, 0xc2, 0x04, 0x3b, 0x26, - 0xb0, 0x93, 0xb2, 0x38, 0x7f, 0x21, 0x8e, 0xe4, 0xd5, 0x71, 0x68, 0x12, 0x7e, 0xec, 0x94, 0x07, - 0x3b, 0x14, 0xc3, 0x4d, 0xeb, 0x4c, 0xa0, 0xaf, 0xc7, 0x35, 0xc3, 0xd0, 0x4d, 0xeb, 0x8c, 0x83, - 0xa7, 0xb9, 0x03, 0x6c, 0x8d, 0xd5, 0x1b, 0xd3, 0xdc, 0x3a, 0xb6, 0xc6, 0xd3, 0xdc, 0x1c, 0x7d, - 0x73, 0x8a, 0x9b, 0x83, 0xc3, 0xd0, 0x0c, 0x07, 0x74, 0xa4, 0xde, 0x8a, 0x43, 0xf3, 0x76, 0x40, - 0x47, 0xe8, 0x31, 0x2c, 0x47, 0xd9, 0x21, 0x84, 0x9e, 0x06, 0x98, 0x9c, 0xaa, 0xb7, 0x13, 0x85, - 0x6d, 0x8d, 0xbb, 0x52, 0x9c, 0xa8, 0x10, 0xaa, 0xaa, 0xc9, 0x0a, 0xa1, 0x51, 0x7e, 0x02, 0x4a, - 0xc7, 0x66, 0xa0, 0xae, 0x24, 0x72, 0xcc, 0x25, 0x91, 0x1d, 0x56, 0x27, 0x91, 0x9d, 0x7a, 0x6c, - 0xa7, 0xeb, 0xd9, 0x91, 0x9d, 0xb0, 0x1f, 0x19, 0xd6, 0x3a, 0xf7, 0x6c, 0xf5, 0x4e, 0x9c, 0x8c, - 0xae, 0x67, 0xb7, 0xce, 0xbd, 0xb8, 0x20, 0x4c, 0x7b, 0xcc, 0x8a, 0xea, 0x6e, 0x6c, 0xb0, 0xc9, - 0x25, 0xec, 0xe4, 0x2f, 0x73, 0xee, 0x07, 0x36, 0x0e, 0x1c, 0xaf, 0xaf, 0xde, 0xe3, 0xa0, 0xaa, - 0x48, 0x7b, 0x28, 0xd5, 0x9a, 0x70, 0xf3, 0x35, 0xa6, 0x3d, 0x7f, 0x28, 0xbf, 0x21, 0x89, 0x8e, - 0x7f, 0x3f, 0xc2, 0x84, 0xb2, 0xc3, 0x36, 0xff, 0x66, 0x30, 0xa6, 0x6e, 0x30, 0xaa, 0x5c, 0xde, - 0x0a, 0x2f, 0x16, 0x34, 0x03, 0x6e, 0x5d, 0xa4, 0x20, 0x43, 0xdf, 0x23, 0x18, 0x7d, 0x03, 0x05, - 0xa9, 0xad, 0xa6, 0xf8, 0x09, 0x6a, 0x65, 0xfe, 0x6d, 0x55, 0x88, 0x44, 0x35, 0xc8, 0x60, 0x4f, - 0x7c, 0x7d, 0x28, 0x3a, 0xfb, 0xa9, 0xbd, 0x84, 0xe5, 0xd7, 0x98, 0x8a, 0x2f, 0xe2, 0xc8, 0xbf, - 0x87, 0xec, 0xdb, 0x86, 0xf9, 0x17, 0xdf, 0x16, 0xa4, 0xc2, 0xcf, 0x10, 0x33, 0x90, 0xe8, 0xb6, - 0xad, 0xbd, 0x07, 0x94, 0x54, 0x96, 0x9e, 0x3d, 0x83, 0xbc, 0xd0, 0x93, 0x8e, 0xa9, 0x73, 0x2f, - 0x02, 0x24, 0x6e, 0x86, 0x5b, 0x3f, 0xc0, 0xed, 0x88, 0x59, 0xcc, 0xdd, 0xc8, 0xb9, 0x89, 0x4b, - 0x8c, 0xd4, 0x85, 0x4b, 0x8c, 0xd8, 0xf3, 0xe8, 0x26, 0x25, 0x9d, 0xf4, 0x5c, 0x5e, 0xa7, 0x68, - 0xa7, 0xa0, 0x4e, 0xf3, 0x4b, 0xff, 0x27, 0x2f, 0xcd, 0x53, 0x9f, 0x73, 0x69, 0x3e, 0x63, 0x25, - 0xdb, 0x3c, 0xc0, 0xd1, 0xc5, 0x95, 0x58, 0xc3, 0xe5, 0x97, 0x57, 0x5a, 0x9b, 0xc7, 0x35, 0xd2, - 0x99, 0x95, 0xf1, 0xd4, 0xd5, 0x32, 0xae, 0xbd, 0x84, 0x1b, 0x6c, 0xa1, 0x89, 0x2b, 0x2d, 0xe1, - 0xc1, 0xd4, 0xb5, 0x56, 0x6a, 0xfa, 0x5a, 0x4b, 0x3b, 0xe6, 0x05, 0x9c, 0x54, 0x96, 0xae, 0xfc, - 0x12, 0x20, 0x06, 0xce, 0xff, 0x07, 0x54, 0x42, 0x33, 0x81, 0xd7, 0x36, 0xa1, 0xc6, 0x68, 0x65, - 0xd0, 0xe2, 0xac, 0x46, 0x29, 0x4b, 0x4d, 0x5e, 0x7e, 0x69, 0xbb, 0xa2, 0x48, 0xa5, 0x42, 0xa2, - 0xcc, 0xc4, 0x25, 0x90, 0xb0, 0xaf, 0xce, 0x4d, 0x91, 0xc4, 0x6d, 0xff, 0x27, 0x0b, 0x8a, 0x0c, - 0xd0, 0x27, 0x64, 0x41, 0x75, 0xb2, 0xb3, 0xd0, 0xa3, 0x69, 0x82, 0x99, 0xed, 0x5b, 0xdf, 0x58, - 0x0c, 0x94, 0x3e, 0xbe, 0x03, 0x88, 0x1b, 0x04, 0xad, 0xcf, 0xd4, 0x9b, 0xec, 0xbd, 0xfa, 0x83, - 0xcb, 0x41, 0x92, 0xd8, 0x11, 0x21, 0x4c, 0xd6, 0x2f, 0xfa, 0xfa, 0x12, 0xcd, 0xc9, 0x1e, 0xaa, - 0x3f, 0xbe, 0x0a, 0x74, 0x62, 0x0d, 0xe1, 0xff, 0x1c, 0x67, 0xaf, 0x61, 0xb2, 0xbc, 0xe7, 0xac, - 0xe1, 0x62, 0x3d, 0xff, 0x08, 0x95, 0x89, 0xea, 0x42, 0x0f, 0x67, 0x7b, 0x75, 0xb1, 0x76, 0xeb, - 0x8f, 0x16, 0xe2, 0xa4, 0x85, 0x1e, 0x14, 0xa3, 0xba, 0x41, 0xda, 0x6c, 0xad, 0x64, 0x15, 0xd6, - 0xd7, 0x2f, 0xc5, 0x08, 0xd6, 0x9d, 0xf7, 0x70, 0xdd, 0xf1, 0xa7, 0x80, 0x3b, 0x95, 0xb0, 0xb4, - 0xde, 0xb2, 0x73, 0xe4, 0xdb, 0xd4, 0x6f, 0x9f, 0xc9, 0x73, 0x65, 0xdf, 0x77, 0x4d, 0xaf, 0xdf, - 0xf0, 0x83, 0xfe, 0xe6, 0xe4, 0xff, 0x9a, 0xd9, 0x53, 0xb8, 0x05, 0x7c, 0x32, 0xc6, 0x5b, 0x1f, - 0xf2, 0xfc, 0x08, 0xfa, 0xcd, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0xd3, 0x7a, 0xae, 0xc5, 0x94, - 0x1e, 0x00, 0x00, + proto.RegisterFile("grpc/channelz/v1/channelz.proto", fileDescriptor_channelz_449295370a82a4c0) +} + +var fileDescriptor_channelz_449295370a82a4c0 = []byte{ + // 2584 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x59, 0x4b, 0x6f, 0xdb, 0xd8, + 0xf5, 0xb7, 0xde, 0xd4, 0xd1, 0x23, 0xf2, 0x4d, 0x26, 0x43, 0x2b, 0x99, 0xb1, 0xff, 0xf4, 0x4c, + 0xc6, 0x93, 0xfc, 0x23, 0xc7, 0x9e, 0x34, 0x28, 0x3a, 0x2d, 0x3a, 0xb6, 0x62, 0xc7, 0x72, 0x1d, + 0x39, 0xa0, 0xe4, 0x49, 0xa6, 0x28, 0xca, 0xa1, 0xc9, 0x6b, 0x99, 0x35, 0x45, 0xaa, 0xbc, 0x57, + 0xf2, 0x24, 0x9b, 0x2e, 0xba, 0xef, 0xb2, 0x28, 0xfa, 0x01, 0xba, 0xe9, 0xa2, 0x40, 0x81, 0x02, + 0xed, 0xb6, 0xdf, 0xa6, 0xdf, 0xa2, 0xb8, 0x0f, 0x3e, 0xf4, 0xb2, 0x14, 0x64, 0xd9, 0x8d, 0x21, + 0x1e, 0xfe, 0xce, 0xef, 0x9c, 0x7b, 0x5e, 0xf7, 0xf2, 0x1a, 0xd6, 0x7b, 0xc1, 0xc0, 0xda, 0xb6, + 0x2e, 0x4d, 0xcf, 0xc3, 0xee, 0xbb, 0xed, 0xd1, 0x4e, 0xf4, 0xbb, 0x31, 0x08, 0x7c, 0xea, 0xa3, + 0x1a, 0x03, 0x34, 0x22, 0xe1, 0x68, 0xa7, 0xbe, 0xd6, 0xf3, 0xfd, 0x9e, 0x8b, 0xb7, 0xf9, 0xfb, + 0xf3, 0xe1, 0xc5, 0xb6, 0xe9, 0xbd, 0x15, 0xe0, 0xfa, 0xa7, 0x93, 0xaf, 0xec, 0x61, 0x60, 0x52, + 0xc7, 0xf7, 0xe4, 0xfb, 0xf5, 0xc9, 0xf7, 0xd4, 0xe9, 0x63, 0x42, 0xcd, 0xfe, 0x60, 0x1e, 0xc1, + 0x75, 0x60, 0x0e, 0x06, 0x38, 0x20, 0xe2, 0xbd, 0xf6, 0xb7, 0x34, 0x14, 0x9a, 0xc2, 0x17, 0xd4, + 0x80, 0x4c, 0x80, 0x2f, 0xd4, 0xd4, 0x46, 0x6a, 0xab, 0xb4, 0x7b, 0xbf, 0x31, 0xe9, 0x67, 0x43, + 0xe2, 0x74, 0x7c, 0xa1, 0x33, 0x20, 0xda, 0x81, 0xac, 0x6d, 0x52, 0x53, 0x4d, 0x73, 0x85, 0x4f, + 0xe6, 0x2a, 0x3c, 0x37, 0xa9, 0xa9, 0x73, 0x28, 0xfa, 0x19, 0x94, 0x24, 0xc0, 0x60, 0xa6, 0x32, + 0x1b, 0x99, 0x85, 0xa6, 0xc0, 0x8a, 0x7e, 0xa3, 0x43, 0xa8, 0x92, 0xe1, 0x79, 0x92, 0x21, 0xcb, + 0x19, 0xd6, 0xa7, 0x19, 0x3a, 0x11, 0x8e, 0x91, 0x54, 0x48, 0xf2, 0x11, 0xfd, 0x04, 0x80, 0xf8, + 0xd6, 0x15, 0xa6, 0x9c, 0x23, 0xc7, 0x39, 0xee, 0xcd, 0xe0, 0xe0, 0x18, 0xa6, 0x5f, 0x24, 0xe1, + 0x4f, 0xed, 0x1f, 0x69, 0x80, 0x98, 0x1c, 0xed, 0x24, 0x83, 0xb6, 0xd0, 0x8f, 0xff, 0xe1, 0xb8, + 0xfd, 0x3b, 0x05, 0xaa, 0x74, 0xaf, 0xe9, 0x7b, 0x1e, 0xb6, 0xa8, 0x33, 0x72, 0xe8, 0xdb, 0x0e, + 0x35, 0x29, 0x46, 0x87, 0x90, 0x23, 0xec, 0x07, 0x8f, 0x63, 0x75, 0xf7, 0xc9, 0xdc, 0x95, 0x4d, + 0xa9, 0x36, 0xf8, 0x5f, 0x5d, 0xa8, 0x6b, 0xbf, 0x86, 0x9c, 0x20, 0x2c, 0x41, 0xe1, 0xac, 0xfd, + 0x8b, 0xf6, 0xe9, 0xeb, 0x76, 0x6d, 0x05, 0x29, 0x90, 0x6d, 0x3d, 0x3f, 0x39, 0xa8, 0xa5, 0x50, + 0x15, 0xa0, 0x79, 0xda, 0x6e, 0x1f, 0x34, 0xbb, 0xad, 0xf6, 0x8b, 0x5a, 0x1a, 0x15, 0x21, 0xa7, + 0x1f, 0xec, 0x3d, 0xff, 0xae, 0x96, 0x41, 0x1f, 0xc1, 0x6a, 0x57, 0xdf, 0x6b, 0x77, 0x5a, 0x07, + 0xed, 0xae, 0x71, 0xb8, 0xd7, 0x3a, 0x39, 0xd3, 0x0f, 0x6a, 0x59, 0x54, 0x06, 0xa5, 0x73, 0x74, + 0xd6, 0x7d, 0xce, 0x98, 0x72, 0xda, 0x7f, 0xd2, 0x50, 0x4a, 0x64, 0x07, 0x7d, 0x93, 0xf4, 0xbb, + 0xb4, 0xfb, 0x70, 0x79, 0xbf, 0xa5, 0xc7, 0xe8, 0x2e, 0xe4, 0xa9, 0x19, 0xf4, 0x30, 0xe5, 0xe5, + 0x50, 0xd4, 0xe5, 0x13, 0x7a, 0x0a, 0x39, 0x1a, 0x98, 0x16, 0x56, 0x33, 0x9c, 0xf9, 0xd3, 0xb9, + 0xcc, 0x5d, 0x86, 0xd2, 0x05, 0x18, 0x6d, 0x42, 0xc5, 0x32, 0x5d, 0x97, 0x18, 0x84, 0x9a, 0x01, + 0xc5, 0xb6, 0x9a, 0xdd, 0x48, 0x6d, 0x65, 0xf4, 0x32, 0x17, 0x76, 0x84, 0x0c, 0x7d, 0x01, 0xb7, + 0x24, 0x68, 0x68, 0x59, 0x18, 0xdb, 0xd8, 0x56, 0x73, 0x1c, 0x56, 0x15, 0xb0, 0x50, 0x8a, 0xfe, + 0x0f, 0x84, 0xa2, 0x71, 0x61, 0x3a, 0x2e, 0xb6, 0xd5, 0x3c, 0x47, 0x95, 0xb8, 0xec, 0x90, 0x8b, + 0xd0, 0x77, 0x70, 0xcf, 0x35, 0x09, 0x35, 0x98, 0x2c, 0x34, 0x6a, 0x44, 0x43, 0x48, 0x2d, 0x70, + 0xe7, 0xeb, 0x0d, 0x31, 0x85, 0x1a, 0xe1, 0x14, 0x6a, 0x74, 0x43, 0x84, 0xae, 0x32, 0xf5, 0xa6, + 0xe9, 0xba, 0xd2, 0xbb, 0xe8, 0x8d, 0xf6, 0xa7, 0x0c, 0xac, 0x26, 0xd7, 0x78, 0x30, 0xc2, 0x1e, + 0x45, 0x1b, 0x50, 0xb2, 0x31, 0xb1, 0x02, 0x67, 0xc0, 0xc6, 0x20, 0x8f, 0x7b, 0x51, 0x4f, 0x8a, + 0xd0, 0x11, 0x28, 0x04, 0x8f, 0x70, 0xe0, 0xd0, 0xb7, 0x3c, 0xa6, 0xd5, 0xdd, 0xff, 0xbf, 0x39, + 0x78, 0x9c, 0xb8, 0xd1, 0x91, 0x3a, 0x7a, 0xa4, 0x8d, 0x7e, 0x0c, 0xc5, 0x78, 0x29, 0x99, 0x85, + 0x4b, 0x89, 0xc1, 0xe8, 0xe7, 0xe3, 0xfd, 0x9a, 0x5d, 0x3c, 0x52, 0x8f, 0x56, 0xc6, 0x3a, 0xf6, + 0x68, 0xaa, 0x63, 0x73, 0x4b, 0x4d, 0x98, 0xa3, 0x95, 0x89, 0x9e, 0xd5, 0x0e, 0x40, 0x09, 0x97, + 0xc6, 0xcb, 0xbf, 0x6b, 0xc4, 0x8d, 0x51, 0x82, 0x42, 0xb3, 0x6b, 0xb4, 0xda, 0x87, 0xa7, 0xb2, + 0x37, 0xba, 0xc6, 0xeb, 0x3d, 0xbd, 0x2d, 0x7a, 0xa3, 0x0c, 0x4a, 0xb3, 0x6b, 0x1c, 0xe8, 0xfa, + 0xa9, 0x5e, 0xcb, 0xec, 0x97, 0xa0, 0x68, 0x5d, 0x3a, 0xae, 0xcd, 0x7c, 0x61, 0xbd, 0x5c, 0x4e, + 0x46, 0x10, 0x3d, 0x84, 0x55, 0x6f, 0xd8, 0x37, 0x30, 0x8b, 0x24, 0x31, 0x5c, 0xbf, 0xd7, 0xc3, + 0x36, 0xcf, 0x4d, 0x46, 0xbf, 0xe5, 0x0d, 0xfb, 0x3c, 0xc2, 0xe4, 0x84, 0x8b, 0x51, 0x0b, 0x90, + 0x15, 0x60, 0xbe, 0x8b, 0x25, 0x2a, 0x25, 0xbd, 0x30, 0xbc, 0xab, 0xa1, 0x56, 0x24, 0x42, 0x5f, + 0x43, 0x5e, 0x98, 0x94, 0x13, 0x71, 0x73, 0x89, 0x44, 0xeb, 0x52, 0x45, 0xb3, 0x00, 0xe2, 0xf0, + 0xa3, 0x4f, 0x20, 0x0c, 0xbf, 0xe1, 0x84, 0xae, 0x17, 0xa5, 0xa4, 0x65, 0x23, 0x04, 0x59, 0xcf, + 0xec, 0x63, 0xd9, 0xa4, 0xfc, 0xf7, 0x71, 0x56, 0xc9, 0xd4, 0xb2, 0xc7, 0x59, 0x25, 0x5b, 0xcb, + 0x1d, 0x67, 0x95, 0x5c, 0x2d, 0x7f, 0x9c, 0x55, 0xf2, 0xb5, 0xc2, 0x71, 0x56, 0x29, 0xd4, 0x94, + 0xe3, 0xac, 0xa2, 0xd4, 0x8a, 0x9a, 0x0b, 0x95, 0xb1, 0xfc, 0xb0, 0x0e, 0x4d, 0x24, 0xd6, 0xb1, + 0x79, 0x8b, 0x64, 0xf4, 0x72, 0x2c, 0x4c, 0x58, 0x53, 0xc6, 0xac, 0xa5, 0x6a, 0xe9, 0xe3, 0xac, + 0x92, 0xae, 0x65, 0xe6, 0x59, 0xd6, 0xbe, 0x87, 0x62, 0x34, 0x7b, 0xd1, 0x3d, 0x90, 0xd3, 0x97, + 0x59, 0xc9, 0x70, 0x2b, 0x8a, 0x10, 0x24, 0x2c, 0x64, 0xe7, 0x5a, 0x98, 0xbd, 0x1e, 0x66, 0x01, + 0x07, 0x23, 0x1c, 0x84, 0x16, 0xf8, 0x03, 0xb3, 0x90, 0x93, 0x16, 0xb8, 0x20, 0x61, 0x21, 0xbf, + 0xd4, 0x1a, 0x62, 0x0b, 0x7f, 0x4d, 0x41, 0x5e, 0x98, 0x40, 0x8f, 0x93, 0x7b, 0xeb, 0xac, 0x7d, + 0x26, 0xf4, 0x44, 0xec, 0xab, 0x4f, 0xc6, 0xf6, 0xd5, 0xfb, 0xf3, 0xf0, 0x89, 0x6d, 0xf5, 0x1b, + 0xa8, 0xb8, 0x0e, 0xa1, 0xd8, 0x33, 0x44, 0x60, 0x64, 0x19, 0xdd, 0xb8, 0xa5, 0x95, 0x85, 0x86, + 0x10, 0x68, 0x7f, 0x60, 0xa7, 0x81, 0x88, 0x36, 0x9e, 0xda, 0xa9, 0x0f, 0x9a, 0xda, 0xe9, 0xe5, + 0xa6, 0x76, 0x66, 0xa9, 0xa9, 0x9d, 0x7d, 0xef, 0xa9, 0x9d, 0xfb, 0x80, 0xa9, 0xfd, 0x97, 0x34, + 0xe4, 0x45, 0x6c, 0x16, 0xa7, 0x2f, 0x8a, 0xe9, 0x92, 0xe9, 0xe3, 0xf8, 0x44, 0xfa, 0xb6, 0x21, + 0xe7, 0xfa, 0x96, 0xe9, 0xca, 0xd9, 0xbc, 0x36, 0xad, 0xb2, 0x67, 0xdb, 0x01, 0x26, 0x44, 0x17, + 0x38, 0xb4, 0x03, 0xf9, 0x00, 0xf7, 0x7d, 0x8a, 0xe5, 0x44, 0xbe, 0x41, 0x43, 0x02, 0xd1, 0x33, + 0xb6, 0x9b, 0x58, 0x43, 0xbe, 0x9b, 0x44, 0x71, 0x99, 0x2e, 0x2c, 0x81, 0xd0, 0x23, 0x2c, 0x5a, + 0x87, 0x92, 0x60, 0x30, 0x12, 0x5d, 0x00, 0x42, 0xd4, 0x36, 0xfb, 0x58, 0xfb, 0x7d, 0x01, 0x20, + 0x5e, 0x11, 0x4b, 0x2f, 0xa1, 0x01, 0x36, 0xfb, 0x71, 0x15, 0x88, 0x21, 0x54, 0x95, 0xe2, 0xb0, + 0x0e, 0x1e, 0xc1, 0x6a, 0x04, 0x8c, 0x2a, 0x41, 0x14, 0x4c, 0x2d, 0x84, 0x46, 0xb5, 0xf0, 0x39, + 0x84, 0xea, 0x61, 0x35, 0x88, 0x9a, 0xa9, 0x48, 0xa9, 0xac, 0x87, 0x4d, 0xa8, 0xf4, 0x31, 0x21, + 0x66, 0x0f, 0x13, 0x83, 0x60, 0x8f, 0x86, 0xc7, 0x86, 0x50, 0xd8, 0x61, 0x3b, 0xef, 0x23, 0x58, + 0x8d, 0x40, 0x01, 0xb6, 0xb0, 0x33, 0x8a, 0x0e, 0x0e, 0xb5, 0xf0, 0x85, 0x2e, 0xe5, 0x68, 0x0b, + 0x6a, 0x57, 0x18, 0x0f, 0x0c, 0xd3, 0x75, 0x46, 0x21, 0xa9, 0x38, 0x3e, 0x54, 0x99, 0x7c, 0x8f, + 0x8b, 0x39, 0xed, 0x25, 0x6c, 0xf2, 0x5a, 0xe4, 0x19, 0x32, 0x84, 0x5f, 0x06, 0x1f, 0xf5, 0xef, + 0x79, 0x92, 0x58, 0x67, 0x34, 0x27, 0x8c, 0xa5, 0xc3, 0x49, 0x9a, 0x82, 0x23, 0xde, 0x2d, 0x7e, + 0x03, 0x9f, 0x71, 0x4b, 0x32, 0x2f, 0x73, 0x4d, 0x29, 0x0b, 0x4d, 0x6d, 0x30, 0x1e, 0x9d, 0xd3, + 0xcc, 0xb1, 0x15, 0x76, 0x98, 0x0c, 0x0c, 0x0f, 0x40, 0xc2, 0x44, 0x71, 0xb9, 0x0e, 0x7b, 0x29, + 0xb4, 0x59, 0x9c, 0x62, 0x6a, 0x13, 0xd6, 0xc7, 0xa8, 0xc3, 0x5c, 0x24, 0xe8, 0x61, 0x21, 0xfd, + 0xfd, 0x04, 0x7d, 0x98, 0xb4, 0xd8, 0xc4, 0xb7, 0xb0, 0x26, 0xd2, 0x71, 0xe1, 0xfa, 0xd7, 0x86, + 0xe5, 0x7b, 0x34, 0xf0, 0x5d, 0xe3, 0xda, 0xf1, 0x6c, 0xff, 0x5a, 0x2d, 0x85, 0xfd, 0x3c, 0x41, + 0xde, 0xf2, 0xe8, 0xb3, 0xa7, 0xdf, 0x9a, 0xee, 0x10, 0xeb, 0x77, 0xb9, 0xf6, 0xa1, 0xeb, 0x5f, + 0x37, 0x85, 0xee, 0x6b, 0xae, 0x8a, 0xde, 0x40, 0x5d, 0x06, 0x7f, 0x16, 0x71, 0x79, 0x31, 0xf1, + 0xc7, 0x42, 0x7d, 0x9a, 0xf9, 0x19, 0xe4, 0x7d, 0x71, 0x22, 0xac, 0xf0, 0x11, 0xfe, 0xe9, 0xbc, + 0xf1, 0x71, 0xca, 0x51, 0xba, 0x44, 0x6b, 0xff, 0xcc, 0x40, 0x41, 0xb6, 0x3c, 0x7a, 0x09, 0x15, + 0x6a, 0x0d, 0x9c, 0x81, 0x61, 0x0a, 0x81, 0x9c, 0x5c, 0x0f, 0xe6, 0x0e, 0x89, 0x46, 0xd7, 0x1a, + 0xb4, 0x06, 0xf2, 0xe1, 0x68, 0x45, 0x2f, 0x73, 0xf5, 0x90, 0xee, 0x05, 0x94, 0x86, 0x36, 0x89, + 0xc8, 0xc4, 0x58, 0xfb, 0x6c, 0x3e, 0xd9, 0x99, 0x4d, 0x62, 0x2a, 0x18, 0x46, 0x4f, 0xcc, 0x2f, + 0x9f, 0x5e, 0xe2, 0x20, 0xa2, 0xca, 0x2c, 0xf2, 0xeb, 0x94, 0xc1, 0x13, 0x7e, 0xf9, 0x89, 0xe7, + 0xfa, 0x1e, 0x94, 0x93, 0x7e, 0xb3, 0x93, 0xcf, 0xc4, 0x9a, 0xcb, 0x7a, 0x31, 0x5e, 0x06, 0x82, + 0xec, 0xc0, 0x0f, 0xc4, 0xe7, 0x49, 0x4e, 0xe7, 0xbf, 0xeb, 0x5b, 0x00, 0xb1, 0xb7, 0xa8, 0x0e, + 0xca, 0x85, 0xe3, 0x62, 0x3e, 0xe7, 0xc4, 0x79, 0x3c, 0x7a, 0xae, 0xb7, 0xa1, 0x9c, 0x74, 0x26, + 0x3a, 0x15, 0xa4, 0xe2, 0x53, 0x01, 0x7a, 0x08, 0xb9, 0x11, 0xcb, 0xae, 0x0c, 0xd1, 0x9d, 0xa9, + 0x02, 0xd8, 0xf3, 0xde, 0xea, 0x02, 0xb2, 0x5f, 0x84, 0x82, 0xf4, 0x54, 0xfb, 0x63, 0x86, 0x9d, + 0x6c, 0xe5, 0xb8, 0xdd, 0x85, 0x0c, 0x75, 0xc9, 0xfc, 0x6d, 0x37, 0x04, 0x36, 0xba, 0x2e, 0x8b, + 0x08, 0x03, 0xb3, 0x8f, 0x37, 0x1e, 0x18, 0x69, 0x77, 0xeb, 0x06, 0x2d, 0xbe, 0x86, 0xf0, 0xe9, + 0x68, 0x45, 0x17, 0x8a, 0xf5, 0x7f, 0xa5, 0x20, 0xd3, 0x75, 0x09, 0xfa, 0x1c, 0x2a, 0x84, 0x9a, + 0x9e, 0x6d, 0x06, 0xb6, 0x11, 0x2f, 0x8f, 0x45, 0x3e, 0x14, 0xb3, 0x91, 0x8f, 0xd6, 0x01, 0x44, + 0x22, 0xe3, 0xa3, 0xe4, 0xd1, 0x8a, 0x5e, 0xe4, 0x32, 0x0e, 0x78, 0x04, 0xab, 0xa2, 0xef, 0x2c, + 0x1c, 0x50, 0xe7, 0xc2, 0xb1, 0xd8, 0xa7, 0x65, 0x86, 0x67, 0xa4, 0xc6, 0x5f, 0x34, 0x63, 0x39, + 0x7a, 0x0c, 0x48, 0x36, 0x53, 0x12, 0x9d, 0xe5, 0xe8, 0x55, 0xf1, 0x26, 0x01, 0xdf, 0xaf, 0x42, + 0xd9, 0x72, 0x06, 0xcc, 0x3a, 0x19, 0x3a, 0x14, 0xd7, 0x4f, 0xa1, 0x32, 0xb6, 0xaa, 0x0f, 0x4e, + 0x4d, 0x01, 0x72, 0x7d, 0xdf, 0xc6, 0xae, 0xe6, 0x41, 0x39, 0xd9, 0x6b, 0x33, 0x89, 0xef, 0x24, + 0x89, 0x8b, 0x92, 0x02, 0x3d, 0x05, 0x30, 0x6d, 0xdb, 0x61, 0x5a, 0xd1, 0xae, 0x3e, 0xdb, 0x66, + 0x02, 0xa7, 0x9d, 0xc0, 0xed, 0xa4, 0x3d, 0x36, 0xc6, 0xfc, 0x21, 0x45, 0x3f, 0x02, 0x25, 0xbc, + 0x2d, 0x93, 0x75, 0xb1, 0x36, 0x45, 0xf5, 0x5c, 0x02, 0xf4, 0x08, 0xaa, 0x59, 0x80, 0x92, 0x6c, + 0x27, 0x8e, 0xd7, 0xc3, 0x01, 0xfb, 0x4c, 0x37, 0xd9, 0xe7, 0xbb, 0x58, 0x85, 0xa2, 0xcb, 0xa7, + 0x31, 0x23, 0xe9, 0xe5, 0x8d, 0xfc, 0x5d, 0x99, 0xf0, 0xd9, 0x1a, 0xb4, 0xbc, 0x0b, 0x9f, 0xf5, + 0x22, 0x9b, 0x21, 0x46, 0x7c, 0xa9, 0x50, 0xd1, 0x8b, 0x4c, 0x22, 0x6e, 0x35, 0x34, 0x31, 0xa1, + 0x0c, 0xcb, 0x94, 0x88, 0x34, 0x47, 0x94, 0x98, 0xb0, 0x69, 0x0a, 0xcc, 0x97, 0x50, 0xe3, 0x98, + 0x00, 0xd3, 0xc0, 0xf4, 0x48, 0xdf, 0xa1, 0x62, 0x60, 0x54, 0xf4, 0x5b, 0x4c, 0xae, 0xc7, 0x62, + 0x76, 0x46, 0xe1, 0xd0, 0x41, 0xe0, 0x9f, 0x63, 0xc2, 0x4b, 0xa7, 0xa2, 0x73, 0x07, 0x5e, 0x71, + 0x09, 0x3b, 0x4a, 0x72, 0xc0, 0xb9, 0x69, 0x5d, 0xf9, 0x17, 0xe2, 0x1b, 0x54, 0x9a, 0xdb, 0x17, + 0xa2, 0x08, 0x22, 0xe6, 0x29, 0xe1, 0x9b, 0xbc, 0x84, 0x88, 0xa5, 0x11, 0xf4, 0x00, 0x6e, 0x89, + 0x45, 0x79, 0xb6, 0x71, 0x4d, 0x2c, 0xd3, 0xc5, 0x7c, 0x37, 0xaf, 0xe8, 0x7c, 0x31, 0x1d, 0xcf, + 0x7e, 0xcd, 0x85, 0x11, 0x2e, 0xb0, 0x46, 0x21, 0x4e, 0x89, 0x71, 0xba, 0x35, 0x92, 0xb8, 0x35, + 0x50, 0x04, 0x8e, 0xfa, 0x7c, 0x23, 0xad, 0xe8, 0x05, 0x0e, 0xa0, 0x7e, 0xf4, 0xca, 0xa4, 0x3e, + 0xdf, 0x04, 0xe5, 0xab, 0x3d, 0xea, 0xa3, 0x0d, 0xe9, 0x28, 0xf3, 0xa2, 0x4f, 0x08, 0xdf, 0xc6, + 0xe4, 0x6a, 0x3b, 0x9e, 0xfd, 0x92, 0x90, 0x08, 0xc1, 0xec, 0x33, 0x44, 0x39, 0x46, 0xe8, 0xd6, + 0x88, 0x21, 0xc2, 0xc5, 0x0e, 0x3d, 0xd3, 0xba, 0xc2, 0xb6, 0x5a, 0x89, 0x17, 0x7b, 0x26, 0x44, + 0x51, 0x4c, 0x89, 0x40, 0x54, 0x13, 0x56, 0x04, 0xe0, 0x1e, 0xf0, 0x84, 0x1a, 0xae, 0x4f, 0xa8, + 0x7a, 0x8b, 0xbf, 0xe6, 0x3e, 0x9f, 0xf8, 0x84, 0x46, 0x06, 0x64, 0xf2, 0xd4, 0x5a, 0x6c, 0x40, + 0x26, 0x2e, 0x82, 0x5c, 0x30, 0x3a, 0x4a, 0xd4, 0xd5, 0x18, 0x72, 0x28, 0x44, 0xe8, 0x31, 0xdc, + 0x16, 0x26, 0xd8, 0x31, 0x81, 0x9d, 0x94, 0xc5, 0xf9, 0x0b, 0x71, 0x24, 0xaf, 0x8e, 0x13, 0x93, + 0xf0, 0x63, 0xa7, 0x3c, 0xd8, 0xa1, 0x18, 0x6e, 0x5a, 0x57, 0x02, 0x7d, 0x3b, 0xae, 0x19, 0x86, + 0xde, 0xb3, 0xae, 0x38, 0x78, 0x9a, 0x3b, 0xc0, 0xd6, 0x48, 0xbd, 0x33, 0xcd, 0xad, 0x63, 0x6b, + 0x34, 0xcd, 0xcd, 0xd1, 0x1f, 0x4d, 0x71, 0x73, 0x70, 0x18, 0x9a, 0x41, 0x9f, 0x0e, 0xd5, 0xbb, + 0x71, 0x68, 0x5e, 0xf5, 0xe9, 0x10, 0x3d, 0x84, 0xd5, 0x28, 0x3b, 0x84, 0xd0, 0xcb, 0x00, 0x93, + 0x4b, 0xf5, 0xe3, 0x44, 0x61, 0x5b, 0xa3, 0x8e, 0x14, 0x27, 0x2a, 0x84, 0xaa, 0x6a, 0xb2, 0x42, + 0x68, 0x94, 0x9f, 0x80, 0xd2, 0x91, 0x19, 0xa8, 0x6b, 0x89, 0x1c, 0x73, 0x49, 0x64, 0x87, 0xd5, + 0x49, 0x64, 0xa7, 0x1e, 0xdb, 0xe9, 0x78, 0x76, 0x64, 0x27, 0xec, 0x47, 0x86, 0xb5, 0xae, 0x3d, + 0x5b, 0xbd, 0x17, 0x27, 0xa3, 0xe3, 0xd9, 0xcd, 0x6b, 0x2f, 0x2e, 0x08, 0xd3, 0x1e, 0xb1, 0xa2, + 0xba, 0x1f, 0x1b, 0xdc, 0xe3, 0x12, 0x76, 0xf2, 0x97, 0x39, 0xf7, 0x03, 0x1b, 0x07, 0x8e, 0xd7, + 0x53, 0x3f, 0xe1, 0xa0, 0xaa, 0x48, 0x7b, 0x28, 0xd5, 0xce, 0xe1, 0xa3, 0x17, 0x98, 0x76, 0xfd, + 0x81, 0xfc, 0x86, 0x24, 0x3a, 0xfe, 0xed, 0x10, 0x13, 0xca, 0x0e, 0xdb, 0xfc, 0x9b, 0xc1, 0x98, + 0xba, 0xc1, 0xa8, 0x72, 0x79, 0x33, 0xba, 0x58, 0x58, 0x87, 0x52, 0xdf, 0xfc, 0xc1, 0x08, 0x30, + 0x19, 0xba, 0x94, 0xc8, 0xcf, 0x06, 0xe8, 0x9b, 0x3f, 0xe8, 0x42, 0xa2, 0x19, 0x70, 0x77, 0xd2, + 0x06, 0x19, 0xf8, 0x1e, 0xc1, 0xe8, 0x2b, 0x28, 0x48, 0x7a, 0x35, 0xc5, 0x8f, 0x58, 0x6b, 0xf3, + 0xaf, 0xb3, 0x42, 0x24, 0xaa, 0x41, 0x06, 0x7b, 0xe2, 0xf3, 0x44, 0xd1, 0xd9, 0x4f, 0xed, 0x57, + 0xb0, 0xfa, 0x02, 0x53, 0xf1, 0xc9, 0x1c, 0x2d, 0xe0, 0x01, 0xfb, 0xf8, 0x61, 0x0b, 0x88, 0xaf, + 0x13, 0x52, 0xe1, 0x77, 0x8a, 0x19, 0x48, 0xf4, 0x32, 0xee, 0xbf, 0x01, 0x94, 0x64, 0x97, 0xae, + 0x3f, 0x81, 0xbc, 0x20, 0x96, 0x9e, 0xab, 0x73, 0xaf, 0x12, 0x24, 0x6e, 0x86, 0xdf, 0xdb, 0x50, + 0x8b, 0x98, 0x43, 0xb7, 0xc7, 0xee, 0x3f, 0x52, 0xe3, 0xf7, 0x1f, 0xda, 0x41, 0x62, 0xa1, 0x33, + 0x3d, 0x49, 0x2d, 0xe3, 0x89, 0xf6, 0x3b, 0xf8, 0x38, 0xa2, 0x11, 0x3b, 0x06, 0x59, 0xc6, 0x7c, + 0x22, 0xa4, 0xd1, 0x1d, 0x50, 0x3a, 0x19, 0xd2, 0xf0, 0x22, 0x68, 0x22, 0xa4, 0x99, 0xa9, 0x90, + 0x5e, 0x82, 0x3a, 0xed, 0x80, 0x5c, 0xce, 0xf8, 0xff, 0x03, 0x52, 0xef, 0xf3, 0xff, 0x80, 0x19, + 0x21, 0xde, 0xe5, 0x11, 0x8b, 0xee, 0xe4, 0xc4, 0x22, 0x6f, 0xbe, 0x97, 0xd3, 0x5a, 0x3c, 0xe1, + 0x91, 0xce, 0xac, 0x5a, 0x4d, 0x2d, 0x57, 0xab, 0xda, 0xd7, 0x70, 0x87, 0x2d, 0x34, 0x71, 0x5b, + 0x27, 0x3c, 0x98, 0xba, 0xb1, 0x4b, 0x4d, 0xdf, 0xd8, 0x69, 0x67, 0xbc, 0x37, 0x93, 0xca, 0xd2, + 0x95, 0x9f, 0x02, 0xc4, 0xc0, 0xf9, 0xff, 0x5b, 0x4b, 0x68, 0x26, 0xf0, 0x5a, 0x4b, 0x54, 0x9d, + 0x0c, 0x5a, 0x9c, 0xf6, 0x28, 0xa7, 0xa9, 0x89, 0x7b, 0x3d, 0x15, 0x0a, 0x64, 0xd8, 0xef, 0x9b, + 0xc1, 0x5b, 0x19, 0xd9, 0xf0, 0x31, 0xac, 0x47, 0x49, 0x95, 0xa8, 0x47, 0x71, 0xf3, 0x35, 0xbf, + 0x1e, 0x85, 0x86, 0xc4, 0xed, 0xfe, 0x39, 0x07, 0x8a, 0x0c, 0xdd, 0x3b, 0x64, 0x41, 0x75, 0x7c, + 0x5a, 0xa0, 0x2f, 0xa6, 0x09, 0x66, 0xce, 0xac, 0xfa, 0xd6, 0x62, 0xa0, 0xf4, 0xf1, 0x35, 0x40, + 0xdc, 0xd3, 0x68, 0x73, 0xa6, 0xde, 0xf8, 0x3c, 0xa9, 0x7f, 0x76, 0x33, 0x48, 0x12, 0x77, 0xa1, + 0x18, 0x49, 0x91, 0x76, 0x83, 0x4a, 0x48, 0xbb, 0x79, 0x23, 0x46, 0xb2, 0x3a, 0x89, 0x41, 0x21, + 0xfb, 0x05, 0x7d, 0x79, 0x83, 0xe2, 0x78, 0x53, 0xd7, 0x1f, 0x2e, 0x03, 0x1d, 0x8b, 0x4c, 0xf8, + 0xef, 0xdb, 0xd9, 0xde, 0x8d, 0xb7, 0xd3, 0x9c, 0xc8, 0x4c, 0xf6, 0xcf, 0xf7, 0x50, 0x19, 0xab, + 0x66, 0xf4, 0x60, 0xb6, 0x57, 0x93, 0xbd, 0x52, 0xff, 0x62, 0x21, 0x6e, 0x3c, 0xf6, 0xe2, 0xa2, + 0x70, 0x4e, 0xec, 0x93, 0x55, 0x3f, 0x2f, 0xf6, 0x63, 0xe5, 0xbc, 0xff, 0x06, 0x6e, 0x3b, 0xfe, + 0x14, 0x70, 0xbf, 0x12, 0x16, 0xec, 0x2b, 0x76, 0x24, 0x7f, 0x95, 0xfa, 0xe5, 0x13, 0x79, 0x44, + 0xef, 0xf9, 0xae, 0xe9, 0xf5, 0x1a, 0x7e, 0xd0, 0xdb, 0x1e, 0xff, 0xb7, 0x3d, 0x7b, 0x0a, 0x77, + 0xd3, 0x77, 0xc6, 0x68, 0xe7, 0x3c, 0xcf, 0x4f, 0xf3, 0x5f, 0xfd, 0x37, 0x00, 0x00, 0xff, 0xff, + 0x54, 0xae, 0x0b, 0x93, 0xdf, 0x1f, 0x00, 0x00, } diff --git a/vendor/google.golang.org/grpc/channelz/service/func_linux.go b/vendor/google.golang.org/grpc/channelz/service/func_linux.go new file mode 100644 index 0000000000000000000000000000000000000000..192c3a1fa5a3f823123edcf594bdf53aca490aae --- /dev/null +++ b/vendor/google.golang.org/grpc/channelz/service/func_linux.go @@ -0,0 +1,105 @@ +// +build !appengine + +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package service + +import ( + "github.com/golang/protobuf/ptypes" + channelzpb "google.golang.org/grpc/channelz/grpc_channelz_v1" + "google.golang.org/grpc/internal/channelz" +) + +func sockoptToProto(skopts *channelz.SocketOptionData) []*channelzpb.SocketOption { + var opts []*channelzpb.SocketOption + if skopts.Linger != nil { + additional, err := ptypes.MarshalAny(&channelzpb.SocketOptionLinger{ + Active: skopts.Linger.Onoff != 0, + Duration: convertToPtypesDuration(int64(skopts.Linger.Linger), 0), + }) + if err == nil { + opts = append(opts, &channelzpb.SocketOption{ + Name: "SO_LINGER", + Additional: additional, + }) + } + } + if skopts.RecvTimeout != nil { + additional, err := ptypes.MarshalAny(&channelzpb.SocketOptionTimeout{ + Duration: convertToPtypesDuration(int64(skopts.RecvTimeout.Sec), int64(skopts.RecvTimeout.Usec)), + }) + if err == nil { + opts = append(opts, &channelzpb.SocketOption{ + Name: "SO_RCVTIMEO", + Additional: additional, + }) + } + } + if skopts.SendTimeout != nil { + additional, err := ptypes.MarshalAny(&channelzpb.SocketOptionTimeout{ + Duration: convertToPtypesDuration(int64(skopts.SendTimeout.Sec), int64(skopts.SendTimeout.Usec)), + }) + if err == nil { + opts = append(opts, &channelzpb.SocketOption{ + Name: "SO_SNDTIMEO", + Additional: additional, + }) + } + } + if skopts.TCPInfo != nil { + additional, err := ptypes.MarshalAny(&channelzpb.SocketOptionTcpInfo{ + TcpiState: uint32(skopts.TCPInfo.State), + TcpiCaState: uint32(skopts.TCPInfo.Ca_state), + TcpiRetransmits: uint32(skopts.TCPInfo.Retransmits), + TcpiProbes: uint32(skopts.TCPInfo.Probes), + TcpiBackoff: uint32(skopts.TCPInfo.Backoff), + TcpiOptions: uint32(skopts.TCPInfo.Options), + // https://golang.org/pkg/syscall/#TCPInfo + // TCPInfo struct does not contain info about TcpiSndWscale and TcpiRcvWscale. + TcpiRto: skopts.TCPInfo.Rto, + TcpiAto: skopts.TCPInfo.Ato, + TcpiSndMss: skopts.TCPInfo.Snd_mss, + TcpiRcvMss: skopts.TCPInfo.Rcv_mss, + TcpiUnacked: skopts.TCPInfo.Unacked, + TcpiSacked: skopts.TCPInfo.Sacked, + TcpiLost: skopts.TCPInfo.Lost, + TcpiRetrans: skopts.TCPInfo.Retrans, + TcpiFackets: skopts.TCPInfo.Fackets, + TcpiLastDataSent: skopts.TCPInfo.Last_data_sent, + TcpiLastAckSent: skopts.TCPInfo.Last_ack_sent, + TcpiLastDataRecv: skopts.TCPInfo.Last_data_recv, + TcpiLastAckRecv: skopts.TCPInfo.Last_ack_recv, + TcpiPmtu: skopts.TCPInfo.Pmtu, + TcpiRcvSsthresh: skopts.TCPInfo.Rcv_ssthresh, + TcpiRtt: skopts.TCPInfo.Rtt, + TcpiRttvar: skopts.TCPInfo.Rttvar, + TcpiSndSsthresh: skopts.TCPInfo.Snd_ssthresh, + TcpiSndCwnd: skopts.TCPInfo.Snd_cwnd, + TcpiAdvmss: skopts.TCPInfo.Advmss, + TcpiReordering: skopts.TCPInfo.Reordering, + }) + if err == nil { + opts = append(opts, &channelzpb.SocketOption{ + Name: "TCP_INFO", + Additional: additional, + }) + } + } + return opts +} diff --git a/vendor/google.golang.org/grpc/envconfig.go b/vendor/google.golang.org/grpc/channelz/service/func_nonlinux.go similarity index 69% rename from vendor/google.golang.org/grpc/envconfig.go rename to vendor/google.golang.org/grpc/channelz/service/func_nonlinux.go index d50178e5171b8c57dca5c1dc337a23bceef48329..eb53334ed0d1493071a7f4d6707f30762a5ca344 100644 --- a/vendor/google.golang.org/grpc/envconfig.go +++ b/vendor/google.golang.org/grpc/channelz/service/func_nonlinux.go @@ -1,3 +1,5 @@ +// +build !linux appengine + /* * * Copyright 2018 gRPC authors. @@ -16,22 +18,13 @@ * */ -package grpc +package service import ( - "os" - "strings" -) - -const ( - envConfigPrefix = "GRPC_GO_" - envConfigStickinessStr = envConfigPrefix + "STICKINESS" -) - -var ( - envConfigStickinessOn bool + channelzpb "google.golang.org/grpc/channelz/grpc_channelz_v1" + "google.golang.org/grpc/internal/channelz" ) -func init() { - envConfigStickinessOn = strings.EqualFold(os.Getenv(envConfigStickinessStr), "on") +func sockoptToProto(skopts *channelz.SocketOptionData) []*channelzpb.SocketOption { + return nil } diff --git a/vendor/google.golang.org/grpc/channelz/service/service.go b/vendor/google.golang.org/grpc/channelz/service/service.go index 19c016bc7c3ab241d30b57bff8259ab1316ae738..1f72d83cbe01c72611669ca57c6504c473838873 100644 --- a/vendor/google.golang.org/grpc/channelz/service/service.go +++ b/vendor/google.golang.org/grpc/channelz/service/service.go @@ -22,21 +22,34 @@ package service import ( + "context" "net" + "time" "github.com/golang/protobuf/ptypes" + durpb "github.com/golang/protobuf/ptypes/duration" wrpb "github.com/golang/protobuf/ptypes/wrappers" - "golang.org/x/net/context" "google.golang.org/grpc" channelzgrpc "google.golang.org/grpc/channelz/grpc_channelz_v1" channelzpb "google.golang.org/grpc/channelz/grpc_channelz_v1" + "google.golang.org/grpc/codes" "google.golang.org/grpc/connectivity" + "google.golang.org/grpc/credentials" "google.golang.org/grpc/internal/channelz" + "google.golang.org/grpc/status" ) +func init() { + channelz.TurnOn() +} + +func convertToPtypesDuration(sec int64, usec int64) *durpb.Duration { + return ptypes.DurationProto(time.Duration(sec*1e9 + usec*1e3)) +} + // RegisterChannelzServiceToServer registers the channelz service to the given server. func RegisterChannelzServiceToServer(s *grpc.Server) { - channelzgrpc.RegisterChannelzServer(s, &serverImpl{}) + channelzgrpc.RegisterChannelzServer(s, newCZServer()) } func newCZServer() channelzgrpc.ChannelzServer { @@ -62,6 +75,35 @@ func connectivityStateToProto(s connectivity.State) *channelzpb.ChannelConnectiv } } +func channelTraceToProto(ct *channelz.ChannelTrace) *channelzpb.ChannelTrace { + pbt := &channelzpb.ChannelTrace{} + pbt.NumEventsLogged = ct.EventNum + if ts, err := ptypes.TimestampProto(ct.CreationTime); err == nil { + pbt.CreationTimestamp = ts + } + var events []*channelzpb.ChannelTraceEvent + for _, e := range ct.Events { + cte := &channelzpb.ChannelTraceEvent{ + Description: e.Desc, + Severity: channelzpb.ChannelTraceEvent_Severity(e.Severity), + } + if ts, err := ptypes.TimestampProto(e.Timestamp); err == nil { + cte.Timestamp = ts + } + if e.RefID != 0 { + switch e.RefType { + case channelz.RefChannel: + cte.ChildRef = &channelzpb.ChannelTraceEvent_ChannelRef{ChannelRef: &channelzpb.ChannelRef{ChannelId: e.RefID, Name: e.RefName}} + case channelz.RefSubChannel: + cte.ChildRef = &channelzpb.ChannelTraceEvent_SubchannelRef{SubchannelRef: &channelzpb.SubchannelRef{SubchannelId: e.RefID, Name: e.RefName}} + } + } + events = append(events, cte) + } + pbt.Events = events + return pbt +} + func channelMetricToProto(cm *channelz.ChannelMetric) *channelzpb.Channel { c := &channelzpb.Channel{} c.Ref = &channelzpb.ChannelRef{ChannelId: cm.ID, Name: cm.RefName} @@ -93,6 +135,7 @@ func channelMetricToProto(cm *channelz.ChannelMetric) *channelzpb.Channel { sockets = append(sockets, &channelzpb.SocketRef{SocketId: id, Name: ref}) } c.SocketRef = sockets + c.Data.Trace = channelTraceToProto(cm.Trace) return c } @@ -127,9 +170,30 @@ func subChannelMetricToProto(cm *channelz.SubChannelMetric) *channelzpb.Subchann sockets = append(sockets, &channelzpb.SocketRef{SocketId: id, Name: ref}) } sc.SocketRef = sockets + sc.Data.Trace = channelTraceToProto(cm.Trace) return sc } +func securityToProto(se credentials.ChannelzSecurityValue) *channelzpb.Security { + switch v := se.(type) { + case *credentials.TLSChannelzSecurityValue: + return &channelzpb.Security{Model: &channelzpb.Security_Tls_{Tls: &channelzpb.Security_Tls{ + CipherSuite: &channelzpb.Security_Tls_StandardName{StandardName: v.StandardName}, + LocalCertificate: v.LocalCertificate, + RemoteCertificate: v.RemoteCertificate, + }}} + case *credentials.OtherChannelzSecurityValue: + otherSecurity := &channelzpb.Security_OtherSecurity{ + Name: v.Name, + } + if anyval, err := ptypes.MarshalAny(v.Value); err == nil { + otherSecurity.Value = anyval + } + return &channelzpb.Security{Model: &channelzpb.Security_Other{Other: otherSecurity}} + } + return nil +} + func addrToProto(a net.Addr) *channelzpb.Address { switch a.Network() { case "udp": @@ -177,6 +241,13 @@ func socketMetricToProto(sm *channelz.SocketMetric) *channelzpb.Socket { s.Data.LocalFlowControlWindow = &wrpb.Int64Value{Value: sm.SocketData.LocalFlowControlWindow} s.Data.RemoteFlowControlWindow = &wrpb.Int64Value{Value: sm.SocketData.RemoteFlowControlWindow} + if sm.SocketData.SocketOptions != nil { + s.Data.Option = sockoptToProto(sm.SocketData.SocketOptions) + } + if sm.SocketData.Security != nil { + s.Security = securityToProto(sm.SocketData.Security) + } + if sm.SocketData.LocalAddr != nil { s.Local = addrToProto(sm.SocketData.LocalAddr) } @@ -264,3 +335,7 @@ func (s *serverImpl) GetSocket(ctx context.Context, req *channelzpb.GetSocketReq resp := &channelzpb.GetSocketResponse{Socket: socketMetricToProto(metric)} return resp, nil } + +func (s *serverImpl) GetServer(ctx context.Context, req *channelzpb.GetServerRequest) (*channelzpb.GetServerResponse, error) { + return nil, status.Error(codes.Unimplemented, "GetServer not implemented") +} diff --git a/vendor/google.golang.org/grpc/channelz/service/service_sktopt_test.go b/vendor/google.golang.org/grpc/channelz/service/service_sktopt_test.go new file mode 100644 index 0000000000000000000000000000000000000000..d90ada0d4bf3e18abc96255d338c60cde5cb7f8e --- /dev/null +++ b/vendor/google.golang.org/grpc/channelz/service/service_sktopt_test.go @@ -0,0 +1,152 @@ +// +build linux,!appengine +// +build 386 amd64 + +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// SocketOptions is only supported on linux system. The functions defined in +// this file are to parse the socket option field and the test is specifically +// to verify the behavior of socket option parsing. + +package service + +import ( + "context" + "reflect" + "strconv" + "testing" + + "github.com/golang/protobuf/ptypes" + durpb "github.com/golang/protobuf/ptypes/duration" + "golang.org/x/sys/unix" + channelzpb "google.golang.org/grpc/channelz/grpc_channelz_v1" + "google.golang.org/grpc/internal/channelz" +) + +func init() { + // Assign protoToSocketOption to protoToSocketOpt in order to enable socket option + // data conversion from proto message to channelz defined struct. + protoToSocketOpt = protoToSocketOption +} + +func convertToDuration(d *durpb.Duration) (sec int64, usec int64) { + if d != nil { + if dur, err := ptypes.Duration(d); err == nil { + sec = int64(int64(dur) / 1e9) + usec = (int64(dur) - sec*1e9) / 1e3 + } + } + return +} + +func protoToLinger(protoLinger *channelzpb.SocketOptionLinger) *unix.Linger { + linger := &unix.Linger{} + if protoLinger.GetActive() { + linger.Onoff = 1 + } + lv, _ := convertToDuration(protoLinger.GetDuration()) + linger.Linger = int32(lv) + return linger +} + +func protoToSocketOption(skopts []*channelzpb.SocketOption) *channelz.SocketOptionData { + skdata := &channelz.SocketOptionData{} + for _, opt := range skopts { + switch opt.GetName() { + case "SO_LINGER": + protoLinger := &channelzpb.SocketOptionLinger{} + err := ptypes.UnmarshalAny(opt.GetAdditional(), protoLinger) + if err == nil { + skdata.Linger = protoToLinger(protoLinger) + } + case "SO_RCVTIMEO": + protoTimeout := &channelzpb.SocketOptionTimeout{} + err := ptypes.UnmarshalAny(opt.GetAdditional(), protoTimeout) + if err == nil { + skdata.RecvTimeout = protoToTime(protoTimeout) + } + case "SO_SNDTIMEO": + protoTimeout := &channelzpb.SocketOptionTimeout{} + err := ptypes.UnmarshalAny(opt.GetAdditional(), protoTimeout) + if err == nil { + skdata.SendTimeout = protoToTime(protoTimeout) + } + case "TCP_INFO": + tcpi := &channelzpb.SocketOptionTcpInfo{} + err := ptypes.UnmarshalAny(opt.GetAdditional(), tcpi) + if err == nil { + skdata.TCPInfo = &unix.TCPInfo{ + State: uint8(tcpi.TcpiState), + Ca_state: uint8(tcpi.TcpiCaState), + Retransmits: uint8(tcpi.TcpiRetransmits), + Probes: uint8(tcpi.TcpiProbes), + Backoff: uint8(tcpi.TcpiBackoff), + Options: uint8(tcpi.TcpiOptions), + Rto: tcpi.TcpiRto, + Ato: tcpi.TcpiAto, + Snd_mss: tcpi.TcpiSndMss, + Rcv_mss: tcpi.TcpiRcvMss, + Unacked: tcpi.TcpiUnacked, + Sacked: tcpi.TcpiSacked, + Lost: tcpi.TcpiLost, + Retrans: tcpi.TcpiRetrans, + Fackets: tcpi.TcpiFackets, + Last_data_sent: tcpi.TcpiLastDataSent, + Last_ack_sent: tcpi.TcpiLastAckSent, + Last_data_recv: tcpi.TcpiLastDataRecv, + Last_ack_recv: tcpi.TcpiLastAckRecv, + Pmtu: tcpi.TcpiPmtu, + Rcv_ssthresh: tcpi.TcpiRcvSsthresh, + Rtt: tcpi.TcpiRtt, + Rttvar: tcpi.TcpiRttvar, + Snd_ssthresh: tcpi.TcpiSndSsthresh, + Snd_cwnd: tcpi.TcpiSndCwnd, + Advmss: tcpi.TcpiAdvmss, + Reordering: tcpi.TcpiReordering} + } + } + } + return skdata +} + +func TestGetSocketOptions(t *testing.T) { + channelz.NewChannelzStorage() + ss := []*dummySocket{ + { + socketOptions: &channelz.SocketOptionData{ + Linger: &unix.Linger{Onoff: 1, Linger: 2}, + RecvTimeout: &unix.Timeval{Sec: 10, Usec: 1}, + SendTimeout: &unix.Timeval{}, + TCPInfo: &unix.TCPInfo{State: 1}, + }, + }, + } + svr := newCZServer() + ids := make([]int64, len(ss)) + svrID := channelz.RegisterServer(&dummyServer{}, "") + for i, s := range ss { + ids[i] = channelz.RegisterNormalSocket(s, svrID, strconv.Itoa(i)) + } + for i, s := range ss { + resp, _ := svr.GetSocket(context.Background(), &channelzpb.GetSocketRequest{SocketId: ids[i]}) + metrics := resp.GetSocket() + if !reflect.DeepEqual(metrics.GetRef(), &channelzpb.SocketRef{SocketId: ids[i], Name: strconv.Itoa(i)}) || !reflect.DeepEqual(socketProtoToStruct(metrics), s) { + t.Fatalf("resp.GetSocket() want: metrics.GetRef() = %#v and %#v, got: metrics.GetRef() = %#v and %#v", &channelzpb.SocketRef{SocketId: ids[i], Name: strconv.Itoa(i)}, s, metrics.GetRef(), socketProtoToStruct(metrics)) + } + } +} diff --git a/vendor/google.golang.org/grpc/channelz/service/service_test.go b/vendor/google.golang.org/grpc/channelz/service/service_test.go index 398cd6c97a0762e4240b1bdbf26f86e7a7ada8ec..26ef41314c2a323f2479945798961869e5294785 100644 --- a/vendor/google.golang.org/grpc/channelz/service/service_test.go +++ b/vendor/google.golang.org/grpc/channelz/service/service_test.go @@ -19,16 +19,19 @@ package service import ( + "context" + "fmt" "net" "reflect" "strconv" "testing" "time" + "github.com/golang/protobuf/proto" "github.com/golang/protobuf/ptypes" - "golang.org/x/net/context" channelzpb "google.golang.org/grpc/channelz/grpc_channelz_v1" "google.golang.org/grpc/connectivity" + "google.golang.org/grpc/credentials" "google.golang.org/grpc/internal/channelz" ) @@ -36,11 +39,19 @@ func init() { channelz.TurnOn() } +type protoToSocketOptFunc func([]*channelzpb.SocketOption) *channelz.SocketOptionData + +// protoToSocketOpt is used in function socketProtoToStruct to extract socket option +// data from unmarshaled proto message. +// It is only defined under linux, non-appengine environment on x86 architecture. +var protoToSocketOpt protoToSocketOptFunc + // emptyTime is used for detecting unset value of time.Time type. // For go1.7 and earlier, ptypes.Timestamp will fill in the loc field of time.Time // with &utcLoc. However zero value of a time.Time type value loc field is nil. // This behavior will make reflect.DeepEqual fail upon unset time.Time field, // and cause false positive fatal error. +// TODO: Go1.7 is no longer supported - does this need a change? var emptyTime time.Time type dummyChannel struct { @@ -92,11 +103,11 @@ type dummySocket struct { lastMessageReceivedTimestamp time.Time localFlowControlWindow int64 remoteFlowControlWindow int64 - //socket options - localAddr net.Addr - remoteAddr net.Addr - // Security - remoteName string + socketOptions *channelz.SocketOptionData + localAddr net.Addr + remoteAddr net.Addr + security credentials.ChannelzSecurityValue + remoteName string } func (d *dummySocket) ChannelzMetric() *channelz.SocketInternalMetric { @@ -113,11 +124,11 @@ func (d *dummySocket) ChannelzMetric() *channelz.SocketInternalMetric { LastMessageReceivedTimestamp: d.lastMessageReceivedTimestamp, LocalFlowControlWindow: d.localFlowControlWindow, RemoteFlowControlWindow: d.remoteFlowControlWindow, - //socket options - LocalAddr: d.localAddr, - RemoteAddr: d.remoteAddr, - // Security - RemoteName: d.remoteName, + SocketOptions: d.socketOptions, + LocalAddr: d.localAddr, + RemoteAddr: d.remoteAddr, + Security: d.security, + RemoteName: d.remoteName, } } @@ -164,21 +175,6 @@ func serverProtoToStruct(s *channelzpb.Server) *dummyServer { return ds } -func protoToAddr(a *channelzpb.Address) net.Addr { - switch v := a.Address.(type) { - case *channelzpb.Address_TcpipAddress: - if port := v.TcpipAddress.GetPort(); port != 0 { - return &net.TCPAddr{IP: v.TcpipAddress.GetIpAddress(), Port: int(port)} - } - return &net.IPAddr{IP: v.TcpipAddress.GetIpAddress()} - case *channelzpb.Address_UdsAddress_: - return &net.UnixAddr{Name: v.UdsAddress.GetFilename(), Net: "unix"} - case *channelzpb.Address_OtherAddress_: - // TODO: - } - return nil -} - func socketProtoToStruct(s *channelzpb.Socket) *dummySocket { ds := &dummySocket{} pdata := s.GetData() @@ -214,6 +210,12 @@ func socketProtoToStruct(s *channelzpb.Socket) *dummySocket { if v := pdata.GetRemoteFlowControlWindow(); v != nil { ds.remoteFlowControlWindow = v.Value } + if v := pdata.GetOption(); v != nil && protoToSocketOpt != nil { + ds.socketOptions = protoToSocketOpt(v) + } + if v := s.GetSecurity(); v != nil { + ds.security = protoToSecurity(v) + } if local := s.GetLocal(); local != nil { ds.localAddr = protoToAddr(local) } @@ -224,6 +226,36 @@ func socketProtoToStruct(s *channelzpb.Socket) *dummySocket { return ds } +func protoToSecurity(protoSecurity *channelzpb.Security) credentials.ChannelzSecurityValue { + switch v := protoSecurity.Model.(type) { + case *channelzpb.Security_Tls_: + return &credentials.TLSChannelzSecurityValue{StandardName: v.Tls.GetStandardName(), LocalCertificate: v.Tls.GetLocalCertificate(), RemoteCertificate: v.Tls.GetRemoteCertificate()} + case *channelzpb.Security_Other: + sv := &credentials.OtherChannelzSecurityValue{Name: v.Other.GetName()} + var x ptypes.DynamicAny + if err := ptypes.UnmarshalAny(v.Other.GetValue(), &x); err == nil { + sv.Value = x.Message + } + return sv + } + return nil +} + +func protoToAddr(a *channelzpb.Address) net.Addr { + switch v := a.Address.(type) { + case *channelzpb.Address_TcpipAddress: + if port := v.TcpipAddress.GetPort(); port != 0 { + return &net.TCPAddr{IP: v.TcpipAddress.GetIpAddress(), Port: int(port)} + } + return &net.IPAddr{IP: v.TcpipAddress.GetIpAddress()} + case *channelzpb.Address_UdsAddress_: + return &net.UnixAddr{Name: v.UdsAddress.GetFilename(), Net: "unix"} + case *channelzpb.Address_OtherAddress_: + // TODO: + } + return nil +} + func convertSocketRefSliceToMap(sktRefs []*channelzpb.SocketRef) map[int64]string { m := make(map[int64]string) for _, sr := range sktRefs { @@ -232,6 +264,20 @@ func convertSocketRefSliceToMap(sktRefs []*channelzpb.SocketRef) map[int64]strin return m } +type OtherSecurityValue struct { + LocalCertificate []byte `protobuf:"bytes,1,opt,name=local_certificate,json=localCertificate,proto3" json:"local_certificate,omitempty"` + RemoteCertificate []byte `protobuf:"bytes,2,opt,name=remote_certificate,json=remoteCertificate,proto3" json:"remote_certificate,omitempty"` +} + +func (m *OtherSecurityValue) Reset() { *m = OtherSecurityValue{} } +func (m *OtherSecurityValue) String() string { return proto.CompactTextString(m) } +func (*OtherSecurityValue) ProtoMessage() {} + +func init() { + // Ad-hoc registering the proto type here to facilitate UnmarshalAny of OtherSecurityValue. + proto.RegisterType((*OtherSecurityValue)(nil), "grpc.credentials.OtherChannelzSecurityValue") +} + func TestGetTopChannels(t *testing.T) { tcs := []*dummyChannel{ { @@ -357,42 +403,160 @@ func TestGetServerSockets(t *testing.T) { } } +// This test makes a GetServerSockets with a non-zero start ID, and expect only +// sockets with ID >= the given start ID. +func TestGetServerSocketsNonZeroStartID(t *testing.T) { + channelz.NewChannelzStorage() + svrID := channelz.RegisterServer(&dummyServer{}, "") + refNames := []string{"listen socket 1", "normal socket 1", "normal socket 2"} + ids := make([]int64, 3) + ids[0] = channelz.RegisterListenSocket(&dummySocket{}, svrID, refNames[0]) + ids[1] = channelz.RegisterNormalSocket(&dummySocket{}, svrID, refNames[1]) + ids[2] = channelz.RegisterNormalSocket(&dummySocket{}, svrID, refNames[2]) + svr := newCZServer() + // Make GetServerSockets with startID = ids[1]+1, so socket-1 won't be + // included in the response. + resp, _ := svr.GetServerSockets(context.Background(), &channelzpb.GetServerSocketsRequest{ServerId: svrID, StartSocketId: ids[1] + 1}) + if !resp.GetEnd() { + t.Fatalf("resp.GetEnd() want: true, got: %v", resp.GetEnd()) + } + // GetServerSockets only return normal socket-2, socket-1 should be + // filtered by start ID. + want := map[int64]string{ + ids[2]: refNames[2], + } + if !reflect.DeepEqual(convertSocketRefSliceToMap(resp.GetSocketRef()), want) { + t.Fatalf("GetServerSockets want: %#v, got: %#v", want, resp.GetSocketRef()) + } +} + func TestGetChannel(t *testing.T) { channelz.NewChannelzStorage() - refNames := []string{"top channel 1", "nested channel 1", "nested channel 2", "nested channel 3"} + refNames := []string{"top channel 1", "nested channel 1", "sub channel 2", "nested channel 3"} ids := make([]int64, 4) ids[0] = channelz.RegisterChannel(&dummyChannel{}, 0, refNames[0]) + channelz.AddTraceEvent(ids[0], &channelz.TraceEventDesc{ + Desc: "Channel Created", + Severity: channelz.CtINFO, + }) ids[1] = channelz.RegisterChannel(&dummyChannel{}, ids[0], refNames[1]) + channelz.AddTraceEvent(ids[1], &channelz.TraceEventDesc{ + Desc: "Channel Created", + Severity: channelz.CtINFO, + Parent: &channelz.TraceEventDesc{ + Desc: fmt.Sprintf("Nested Channel(id:%d) created", ids[1]), + Severity: channelz.CtINFO, + }, + }) + ids[2] = channelz.RegisterSubChannel(&dummyChannel{}, ids[0], refNames[2]) + channelz.AddTraceEvent(ids[2], &channelz.TraceEventDesc{ + Desc: "SubChannel Created", + Severity: channelz.CtINFO, + Parent: &channelz.TraceEventDesc{ + Desc: fmt.Sprintf("SubChannel(id:%d) created", ids[2]), + Severity: channelz.CtINFO, + }, + }) ids[3] = channelz.RegisterChannel(&dummyChannel{}, ids[1], refNames[3]) + channelz.AddTraceEvent(ids[3], &channelz.TraceEventDesc{ + Desc: "Channel Created", + Severity: channelz.CtINFO, + Parent: &channelz.TraceEventDesc{ + Desc: fmt.Sprintf("Nested Channel(id:%d) created", ids[3]), + Severity: channelz.CtINFO, + }, + }) + channelz.AddTraceEvent(ids[0], &channelz.TraceEventDesc{ + Desc: fmt.Sprintf("Channel Connectivity change to %v", connectivity.Ready), + Severity: channelz.CtINFO, + }) + channelz.AddTraceEvent(ids[0], &channelz.TraceEventDesc{ + Desc: "Resolver returns an empty address list", + Severity: channelz.CtWarning, + }) svr := newCZServer() resp, _ := svr.GetChannel(context.Background(), &channelzpb.GetChannelRequest{ChannelId: ids[0]}) metrics := resp.GetChannel() subChans := metrics.GetSubchannelRef() if len(subChans) != 1 || subChans[0].GetName() != refNames[2] || subChans[0].GetSubchannelId() != ids[2] { - t.Fatalf("GetSubChannelRef() want %#v, got %#v", []*channelzpb.SubchannelRef{{SubchannelId: ids[2], Name: refNames[2]}}, subChans) + t.Fatalf("metrics.GetSubChannelRef() want %#v, got %#v", []*channelzpb.SubchannelRef{{SubchannelId: ids[2], Name: refNames[2]}}, subChans) } nestedChans := metrics.GetChannelRef() if len(nestedChans) != 1 || nestedChans[0].GetName() != refNames[1] || nestedChans[0].GetChannelId() != ids[1] { - t.Fatalf("GetChannelRef() want %#v, got %#v", []*channelzpb.ChannelRef{{ChannelId: ids[1], Name: refNames[1]}}, nestedChans) + t.Fatalf("metrics.GetChannelRef() want %#v, got %#v", []*channelzpb.ChannelRef{{ChannelId: ids[1], Name: refNames[1]}}, nestedChans) + } + trace := metrics.GetData().GetTrace() + want := []struct { + desc string + severity channelzpb.ChannelTraceEvent_Severity + childID int64 + childRef string + }{ + {desc: "Channel Created", severity: channelzpb.ChannelTraceEvent_CT_INFO}, + {desc: fmt.Sprintf("Nested Channel(id:%d) created", ids[1]), severity: channelzpb.ChannelTraceEvent_CT_INFO, childID: ids[1], childRef: refNames[1]}, + {desc: fmt.Sprintf("SubChannel(id:%d) created", ids[2]), severity: channelzpb.ChannelTraceEvent_CT_INFO, childID: ids[2], childRef: refNames[2]}, + {desc: fmt.Sprintf("Channel Connectivity change to %v", connectivity.Ready), severity: channelzpb.ChannelTraceEvent_CT_INFO}, + {desc: "Resolver returns an empty address list", severity: channelzpb.ChannelTraceEvent_CT_WARNING}, } + for i, e := range trace.Events { + if e.GetDescription() != want[i].desc { + t.Fatalf("trace: GetDescription want %#v, got %#v", want[i].desc, e.GetDescription()) + } + if e.GetSeverity() != want[i].severity { + t.Fatalf("trace: GetSeverity want %#v, got %#v", want[i].severity, e.GetSeverity()) + } + if want[i].childID == 0 && (e.GetChannelRef() != nil || e.GetSubchannelRef() != nil) { + t.Fatalf("trace: GetChannelRef() should return nil, as there is no reference") + } + if e.GetChannelRef().GetChannelId() != want[i].childID || e.GetChannelRef().GetName() != want[i].childRef { + if e.GetSubchannelRef().GetSubchannelId() != want[i].childID || e.GetSubchannelRef().GetName() != want[i].childRef { + t.Fatalf("trace: GetChannelRef/GetSubchannelRef want (child ID: %d, child name: %q), got %#v and %#v", want[i].childID, want[i].childRef, e.GetChannelRef(), e.GetSubchannelRef()) + } + } + } resp, _ = svr.GetChannel(context.Background(), &channelzpb.GetChannelRequest{ChannelId: ids[1]}) metrics = resp.GetChannel() nestedChans = metrics.GetChannelRef() if len(nestedChans) != 1 || nestedChans[0].GetName() != refNames[3] || nestedChans[0].GetChannelId() != ids[3] { - t.Fatalf("GetChannelRef() want %#v, got %#v", []*channelzpb.ChannelRef{{ChannelId: ids[3], Name: refNames[3]}}, nestedChans) + t.Fatalf("metrics.GetChannelRef() want %#v, got %#v", []*channelzpb.ChannelRef{{ChannelId: ids[3], Name: refNames[3]}}, nestedChans) } } func TestGetSubChannel(t *testing.T) { + var ( + subchanCreated = "SubChannel Created" + subchanConnectivityChange = fmt.Sprintf("Subchannel Connectivity change to %v", connectivity.Ready) + subChanPickNewAddress = fmt.Sprintf("Subchannel picks a new address %q to connect", "0.0.0.0") + ) channelz.NewChannelzStorage() refNames := []string{"top channel 1", "sub channel 1", "socket 1", "socket 2"} ids := make([]int64, 4) ids[0] = channelz.RegisterChannel(&dummyChannel{}, 0, refNames[0]) + channelz.AddTraceEvent(ids[0], &channelz.TraceEventDesc{ + Desc: "Channel Created", + Severity: channelz.CtINFO, + }) ids[1] = channelz.RegisterSubChannel(&dummyChannel{}, ids[0], refNames[1]) + channelz.AddTraceEvent(ids[1], &channelz.TraceEventDesc{ + Desc: subchanCreated, + Severity: channelz.CtINFO, + Parent: &channelz.TraceEventDesc{ + Desc: fmt.Sprintf("Nested Channel(id:%d) created", ids[0]), + Severity: channelz.CtINFO, + }, + }) ids[2] = channelz.RegisterNormalSocket(&dummySocket{}, ids[1], refNames[2]) ids[3] = channelz.RegisterNormalSocket(&dummySocket{}, ids[1], refNames[3]) + channelz.AddTraceEvent(ids[1], &channelz.TraceEventDesc{ + Desc: subchanConnectivityChange, + Severity: channelz.CtINFO, + }) + channelz.AddTraceEvent(ids[1], &channelz.TraceEventDesc{ + Desc: subChanPickNewAddress, + Severity: channelz.CtINFO, + }) svr := newCZServer() resp, _ := svr.GetSubchannel(context.Background(), &channelzpb.GetSubchannelRequest{SubchannelId: ids[1]}) metrics := resp.GetSubchannel() @@ -401,7 +565,35 @@ func TestGetSubChannel(t *testing.T) { ids[3]: refNames[3], } if !reflect.DeepEqual(convertSocketRefSliceToMap(metrics.GetSocketRef()), want) { - t.Fatalf("GetSocketRef() want %#v: got: %#v", want, metrics.GetSocketRef()) + t.Fatalf("metrics.GetSocketRef() want %#v: got: %#v", want, metrics.GetSocketRef()) + } + + trace := metrics.GetData().GetTrace() + wantTrace := []struct { + desc string + severity channelzpb.ChannelTraceEvent_Severity + childID int64 + childRef string + }{ + {desc: subchanCreated, severity: channelzpb.ChannelTraceEvent_CT_INFO}, + {desc: subchanConnectivityChange, severity: channelzpb.ChannelTraceEvent_CT_INFO}, + {desc: subChanPickNewAddress, severity: channelzpb.ChannelTraceEvent_CT_INFO}, + } + for i, e := range trace.Events { + if e.GetDescription() != wantTrace[i].desc { + t.Fatalf("trace: GetDescription want %#v, got %#v", wantTrace[i].desc, e.GetDescription()) + } + if e.GetSeverity() != wantTrace[i].severity { + t.Fatalf("trace: GetSeverity want %#v, got %#v", wantTrace[i].severity, e.GetSeverity()) + } + if wantTrace[i].childID == 0 && (e.GetChannelRef() != nil || e.GetSubchannelRef() != nil) { + t.Fatalf("trace: GetChannelRef() should return nil, as there is no reference") + } + if e.GetChannelRef().GetChannelId() != wantTrace[i].childID || e.GetChannelRef().GetName() != wantTrace[i].childRef { + if e.GetSubchannelRef().GetSubchannelId() != wantTrace[i].childID || e.GetSubchannelRef().GetName() != wantTrace[i].childRef { + t.Fatalf("trace: GetChannelRef/GetSubchannelRef want (child ID: %d, child name: %q), got %#v and %#v", wantTrace[i].childID, wantTrace[i].childRef, e.GetChannelRef(), e.GetSubchannelRef()) + } + } } } @@ -460,6 +652,23 @@ func TestGetSocket(t *testing.T) { { localAddr: &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 10001}, }, + { + security: &credentials.TLSChannelzSecurityValue{ + StandardName: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + RemoteCertificate: []byte{48, 130, 2, 156, 48, 130, 2, 5, 160}, + }, + }, + { + security: &credentials.OtherChannelzSecurityValue{ + Name: "XXXX", + }, + }, + { + security: &credentials.OtherChannelzSecurityValue{ + Name: "YYYY", + Value: &OtherSecurityValue{LocalCertificate: []byte{1, 2, 3}, RemoteCertificate: []byte{4, 5, 6}}, + }, + }, } svr := newCZServer() ids := make([]int64, len(ss)) diff --git a/vendor/google.golang.org/grpc/grpclb/noimport.go b/vendor/google.golang.org/grpc/channelz/service/util_sktopt_386_test.go similarity index 60% rename from vendor/google.golang.org/grpc/grpclb/noimport.go rename to vendor/google.golang.org/grpc/channelz/service/util_sktopt_386_test.go index b1b24298d41450295e17a0a8961dc40d4a1597e0..cdc2fda4028d411b6f3ad543c73553b9dc8e6960 100644 --- a/vendor/google.golang.org/grpc/grpclb/noimport.go +++ b/vendor/google.golang.org/grpc/channelz/service/util_sktopt_386_test.go @@ -1,3 +1,5 @@ +// +build 386,linux,!appengine + /* * * Copyright 2018 gRPC authors. @@ -16,12 +18,16 @@ * */ -//go:generate protoc --go_out=plugins=:$GOPATH/src grpc_lb_v1/messages/messages.proto -//go:generate protoc --go_out=plugins=grpc:$GOPATH/src grpc_lb_v1/service/service.proto +package service -// Package grpclb is a dummy package for generating code. Look at balancer/grpclb instead. -package grpclb +import ( + "golang.org/x/sys/unix" + channelzpb "google.golang.org/grpc/channelz/grpc_channelz_v1" +) -func init() { - panic("Don't import this package. For grpclb, see package google.golang.org/grpc/balancer/grpclb") +func protoToTime(protoTime *channelzpb.SocketOptionTimeout) *unix.Timeval { + timeout := &unix.Timeval{} + sec, usec := convertToDuration(protoTime.GetDuration()) + timeout.Sec, timeout.Usec = int32(sec), int32(usec) + return timeout } diff --git a/vendor/google.golang.org/grpc/naming/go17.go b/vendor/google.golang.org/grpc/channelz/service/util_sktopt_amd64_test.go similarity index 61% rename from vendor/google.golang.org/grpc/naming/go17.go rename to vendor/google.golang.org/grpc/channelz/service/util_sktopt_amd64_test.go index 57b65d7b88981123e81504e6d597e339b7214ea7..7ebe9c70eb687d74be85b4fee8fc411e6a838d11 100644 --- a/vendor/google.golang.org/grpc/naming/go17.go +++ b/vendor/google.golang.org/grpc/channelz/service/util_sktopt_amd64_test.go @@ -1,8 +1,8 @@ -// +build go1.6,!go1.8 +// +build amd64,linux,!appengine /* * - * Copyright 2017 gRPC authors. + * Copyright 2018 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,17 +18,15 @@ * */ -package naming +package service import ( - "net" - - "golang.org/x/net/context" + "golang.org/x/sys/unix" + channelzpb "google.golang.org/grpc/channelz/grpc_channelz_v1" ) -var ( - lookupHost = func(ctx context.Context, host string) ([]string, error) { return net.LookupHost(host) } - lookupSRV = func(ctx context.Context, service, proto, name string) (string, []*net.SRV, error) { - return net.LookupSRV(service, proto, name) - } -) +func protoToTime(protoTime *channelzpb.SocketOptionTimeout) *unix.Timeval { + timeout := &unix.Timeval{} + timeout.Sec, timeout.Usec = convertToDuration(protoTime.GetDuration()) + return timeout +} diff --git a/vendor/google.golang.org/grpc/clientconn.go b/vendor/google.golang.org/grpc/clientconn.go index 84ba9e5ad72b5e0e00ad4e289d60c1e071e5281d..84b6dbe3eabf93679950cbf7dd2b71337b7a41c2 100644 --- a/vendor/google.golang.org/grpc/clientconn.go +++ b/vendor/google.golang.org/grpc/clientconn.go @@ -19,6 +19,7 @@ package grpc import ( + "context" "errors" "fmt" "math" @@ -26,10 +27,9 @@ import ( "reflect" "strings" "sync" + "sync/atomic" "time" - "golang.org/x/net/context" - "golang.org/x/net/trace" "google.golang.org/grpc/balancer" _ "google.golang.org/grpc/balancer/roundrobin" // To register roundrobin. "google.golang.org/grpc/codes" @@ -39,13 +39,15 @@ import ( "google.golang.org/grpc/internal" "google.golang.org/grpc/internal/backoff" "google.golang.org/grpc/internal/channelz" + "google.golang.org/grpc/internal/envconfig" + "google.golang.org/grpc/internal/grpcsync" + "google.golang.org/grpc/internal/transport" "google.golang.org/grpc/keepalive" + "google.golang.org/grpc/metadata" "google.golang.org/grpc/resolver" _ "google.golang.org/grpc/resolver/dns" // To register dns resolver. _ "google.golang.org/grpc/resolver/passthrough" // To register passthrough resolver. - "google.golang.org/grpc/stats" "google.golang.org/grpc/status" - "google.golang.org/grpc/transport" ) const ( @@ -66,8 +68,6 @@ var ( errConnDrain = errors.New("grpc: the connection is drained") // errConnClosing indicates that the connection is closing. errConnClosing = errors.New("grpc: the connection is closing") - // errConnUnavailable indicates that the connection is unavailable. - errConnUnavailable = errors.New("grpc: the connection is unavailable") // errBalancerClosed indicates that the balancer is closed. errBalancerClosed = errors.New("grpc: balancer is closed") // We use an accessor so that minConnectTimeout can be @@ -83,6 +83,9 @@ var ( // being set for ClientConn. Users should either set one or explicitly // call WithInsecure DialOption to disable security. errNoTransportSecurity = errors.New("grpc: no transport security set (use grpc.WithInsecure() explicitly or set credentials)") + // errTransportCredsAndBundle indicates that creds bundle is used together + // with other individual Transport Credentials. + errTransportCredsAndBundle = errors.New("grpc: credentials.Bundle may not be used with individual TransportCredentials") // errTransportCredentialsMissing indicates that users want to transmit security // information (e.g., oauth2 token) which requires secure connection on an insecure // connection. @@ -90,351 +93,16 @@ var ( // errCredentialsConflict indicates that grpc.WithTransportCredentials() // and grpc.WithInsecure() are both called for a connection. errCredentialsConflict = errors.New("grpc: transport credentials are set for an insecure connection (grpc.WithTransportCredentials() and grpc.WithInsecure() are both called)") - // errNetworkIO indicates that the connection is down due to some network I/O error. - errNetworkIO = errors.New("grpc: failed with network I/O error") ) -// dialOptions configure a Dial call. dialOptions are set by the DialOption -// values passed to Dial. -type dialOptions struct { - unaryInt UnaryClientInterceptor - streamInt StreamClientInterceptor - cp Compressor - dc Decompressor - bs backoff.Strategy - block bool - insecure bool - timeout time.Duration - scChan <-chan ServiceConfig - copts transport.ConnectOptions - callOptions []CallOption - // This is used by v1 balancer dial option WithBalancer to support v1 - // balancer, and also by WithBalancerName dial option. - balancerBuilder balancer.Builder - // This is to support grpclb. - resolverBuilder resolver.Builder - waitForHandshake bool - channelzParentID int64 - disableServiceConfig bool -} - const ( defaultClientMaxReceiveMessageSize = 1024 * 1024 * 4 defaultClientMaxSendMessageSize = math.MaxInt32 + // http2IOBufSize specifies the buffer size for sending frames. + defaultWriteBufSize = 32 * 1024 + defaultReadBufSize = 32 * 1024 ) -// RegisterChannelz turns on channelz service. -// This is an EXPERIMENTAL API. -func RegisterChannelz() { - channelz.TurnOn() -} - -// DialOption configures how we set up the connection. -type DialOption func(*dialOptions) - -// WithWaitForHandshake blocks until the initial settings frame is received from the -// server before assigning RPCs to the connection. -// Experimental API. -func WithWaitForHandshake() DialOption { - return func(o *dialOptions) { - o.waitForHandshake = true - } -} - -// WithWriteBufferSize lets you set the size of write buffer, this determines how much data can be batched -// before doing a write on the wire. -func WithWriteBufferSize(s int) DialOption { - return func(o *dialOptions) { - o.copts.WriteBufferSize = s - } -} - -// WithReadBufferSize lets you set the size of read buffer, this determines how much data can be read at most -// for each read syscall. -func WithReadBufferSize(s int) DialOption { - return func(o *dialOptions) { - o.copts.ReadBufferSize = s - } -} - -// WithInitialWindowSize returns a DialOption which sets the value for initial window size on a stream. -// The lower bound for window size is 64K and any value smaller than that will be ignored. -func WithInitialWindowSize(s int32) DialOption { - return func(o *dialOptions) { - o.copts.InitialWindowSize = s - } -} - -// WithInitialConnWindowSize returns a DialOption which sets the value for initial window size on a connection. -// The lower bound for window size is 64K and any value smaller than that will be ignored. -func WithInitialConnWindowSize(s int32) DialOption { - return func(o *dialOptions) { - o.copts.InitialConnWindowSize = s - } -} - -// WithMaxMsgSize returns a DialOption which sets the maximum message size the client can receive. -// -// Deprecated: use WithDefaultCallOptions(MaxCallRecvMsgSize(s)) instead. -func WithMaxMsgSize(s int) DialOption { - return WithDefaultCallOptions(MaxCallRecvMsgSize(s)) -} - -// WithDefaultCallOptions returns a DialOption which sets the default CallOptions for calls over the connection. -func WithDefaultCallOptions(cos ...CallOption) DialOption { - return func(o *dialOptions) { - o.callOptions = append(o.callOptions, cos...) - } -} - -// WithCodec returns a DialOption which sets a codec for message marshaling and unmarshaling. -// -// Deprecated: use WithDefaultCallOptions(CallCustomCodec(c)) instead. -func WithCodec(c Codec) DialOption { - return WithDefaultCallOptions(CallCustomCodec(c)) -} - -// WithCompressor returns a DialOption which sets a Compressor to use for -// message compression. It has lower priority than the compressor set by -// the UseCompressor CallOption. -// -// Deprecated: use UseCompressor instead. -func WithCompressor(cp Compressor) DialOption { - return func(o *dialOptions) { - o.cp = cp - } -} - -// WithDecompressor returns a DialOption which sets a Decompressor to use for -// incoming message decompression. If incoming response messages are encoded -// using the decompressor's Type(), it will be used. Otherwise, the message -// encoding will be used to look up the compressor registered via -// encoding.RegisterCompressor, which will then be used to decompress the -// message. If no compressor is registered for the encoding, an Unimplemented -// status error will be returned. -// -// Deprecated: use encoding.RegisterCompressor instead. -func WithDecompressor(dc Decompressor) DialOption { - return func(o *dialOptions) { - o.dc = dc - } -} - -// WithBalancer returns a DialOption which sets a load balancer with the v1 API. -// Name resolver will be ignored if this DialOption is specified. -// -// Deprecated: use the new balancer APIs in balancer package and WithBalancerName. -func WithBalancer(b Balancer) DialOption { - return func(o *dialOptions) { - o.balancerBuilder = &balancerWrapperBuilder{ - b: b, - } - } -} - -// WithBalancerName sets the balancer that the ClientConn will be initialized -// with. Balancer registered with balancerName will be used. This function -// panics if no balancer was registered by balancerName. -// -// The balancer cannot be overridden by balancer option specified by service -// config. -// -// This is an EXPERIMENTAL API. -func WithBalancerName(balancerName string) DialOption { - builder := balancer.Get(balancerName) - if builder == nil { - panic(fmt.Sprintf("grpc.WithBalancerName: no balancer is registered for name %v", balancerName)) - } - return func(o *dialOptions) { - o.balancerBuilder = builder - } -} - -// withResolverBuilder is only for grpclb. -func withResolverBuilder(b resolver.Builder) DialOption { - return func(o *dialOptions) { - o.resolverBuilder = b - } -} - -// WithServiceConfig returns a DialOption which has a channel to read the service configuration. -// -// Deprecated: service config should be received through name resolver, as specified here. -// https://github.com/grpc/grpc/blob/master/doc/service_config.md -func WithServiceConfig(c <-chan ServiceConfig) DialOption { - return func(o *dialOptions) { - o.scChan = c - } -} - -// WithBackoffMaxDelay configures the dialer to use the provided maximum delay -// when backing off after failed connection attempts. -func WithBackoffMaxDelay(md time.Duration) DialOption { - return WithBackoffConfig(BackoffConfig{MaxDelay: md}) -} - -// WithBackoffConfig configures the dialer to use the provided backoff -// parameters after connection failures. -// -// Use WithBackoffMaxDelay until more parameters on BackoffConfig are opened up -// for use. -func WithBackoffConfig(b BackoffConfig) DialOption { - - return withBackoff(backoff.Exponential{ - MaxDelay: b.MaxDelay, - }) -} - -// withBackoff sets the backoff strategy used for connectRetryNum after a -// failed connection attempt. -// -// This can be exported if arbitrary backoff strategies are allowed by gRPC. -func withBackoff(bs backoff.Strategy) DialOption { - return func(o *dialOptions) { - o.bs = bs - } -} - -// WithBlock returns a DialOption which makes caller of Dial blocks until the underlying -// connection is up. Without this, Dial returns immediately and connecting the server -// happens in background. -func WithBlock() DialOption { - return func(o *dialOptions) { - o.block = true - } -} - -// WithInsecure returns a DialOption which disables transport security for this ClientConn. -// Note that transport security is required unless WithInsecure is set. -func WithInsecure() DialOption { - return func(o *dialOptions) { - o.insecure = true - } -} - -// WithTransportCredentials returns a DialOption which configures a -// connection level security credentials (e.g., TLS/SSL). -func WithTransportCredentials(creds credentials.TransportCredentials) DialOption { - return func(o *dialOptions) { - o.copts.TransportCredentials = creds - } -} - -// WithPerRPCCredentials returns a DialOption which sets -// credentials and places auth state on each outbound RPC. -func WithPerRPCCredentials(creds credentials.PerRPCCredentials) DialOption { - return func(o *dialOptions) { - o.copts.PerRPCCredentials = append(o.copts.PerRPCCredentials, creds) - } -} - -// WithTimeout returns a DialOption that configures a timeout for dialing a ClientConn -// initially. This is valid if and only if WithBlock() is present. -// -// Deprecated: use DialContext and context.WithTimeout instead. -func WithTimeout(d time.Duration) DialOption { - return func(o *dialOptions) { - o.timeout = d - } -} - -func withContextDialer(f func(context.Context, string) (net.Conn, error)) DialOption { - return func(o *dialOptions) { - o.copts.Dialer = f - } -} - -func init() { - internal.WithContextDialer = withContextDialer - internal.WithResolverBuilder = withResolverBuilder -} - -// WithDialer returns a DialOption that specifies a function to use for dialing network addresses. -// If FailOnNonTempDialError() is set to true, and an error is returned by f, gRPC checks the error's -// Temporary() method to decide if it should try to reconnect to the network address. -func WithDialer(f func(string, time.Duration) (net.Conn, error)) DialOption { - return withContextDialer( - func(ctx context.Context, addr string) (net.Conn, error) { - if deadline, ok := ctx.Deadline(); ok { - return f(addr, deadline.Sub(time.Now())) - } - return f(addr, 0) - }) -} - -// WithStatsHandler returns a DialOption that specifies the stats handler -// for all the RPCs and underlying network connections in this ClientConn. -func WithStatsHandler(h stats.Handler) DialOption { - return func(o *dialOptions) { - o.copts.StatsHandler = h - } -} - -// FailOnNonTempDialError returns a DialOption that specifies if gRPC fails on non-temporary dial errors. -// If f is true, and dialer returns a non-temporary error, gRPC will fail the connection to the network -// address and won't try to reconnect. -// The default value of FailOnNonTempDialError is false. -// This is an EXPERIMENTAL API. -func FailOnNonTempDialError(f bool) DialOption { - return func(o *dialOptions) { - o.copts.FailOnNonTempDialError = f - } -} - -// WithUserAgent returns a DialOption that specifies a user agent string for all the RPCs. -func WithUserAgent(s string) DialOption { - return func(o *dialOptions) { - o.copts.UserAgent = s - } -} - -// WithKeepaliveParams returns a DialOption that specifies keepalive parameters for the client transport. -func WithKeepaliveParams(kp keepalive.ClientParameters) DialOption { - return func(o *dialOptions) { - o.copts.KeepaliveParams = kp - } -} - -// WithUnaryInterceptor returns a DialOption that specifies the interceptor for unary RPCs. -func WithUnaryInterceptor(f UnaryClientInterceptor) DialOption { - return func(o *dialOptions) { - o.unaryInt = f - } -} - -// WithStreamInterceptor returns a DialOption that specifies the interceptor for streaming RPCs. -func WithStreamInterceptor(f StreamClientInterceptor) DialOption { - return func(o *dialOptions) { - o.streamInt = f - } -} - -// WithAuthority returns a DialOption that specifies the value to be used as -// the :authority pseudo-header. This value only works with WithInsecure and -// has no effect if TransportCredentials are present. -func WithAuthority(a string) DialOption { - return func(o *dialOptions) { - o.copts.Authority = a - } -} - -// WithChannelzParentID returns a DialOption that specifies the channelz ID of current ClientConn's -// parent. This function is used in nested channel creation (e.g. grpclb dial). -func WithChannelzParentID(id int64) DialOption { - return func(o *dialOptions) { - o.channelzParentID = id - } -} - -// WithDisableServiceConfig returns a DialOption that causes grpc to ignore any -// service config provided by the resolver and provides a hint to the resolver -// to not fetch service configs. -func WithDisableServiceConfig() DialOption { - return func(o *dialOptions) { - o.disableServiceConfig = true - } -} - // Dial creates a client connection to the given target. func Dial(target string, opts ...DialOption) (*ClientConn, error) { return DialContext(context.Background(), target, opts...) @@ -458,32 +126,51 @@ func Dial(target string, opts ...DialOption) (*ClientConn, error) { // e.g. to use dns resolver, a "dns:///" prefix should be applied to the target. func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *ClientConn, err error) { cc := &ClientConn{ - target: target, - csMgr: &connectivityStateManager{}, - conns: make(map[*addrConn]struct{}), - - blockingpicker: newPickerWrapper(), - } + target: target, + csMgr: &connectivityStateManager{}, + conns: make(map[*addrConn]struct{}), + dopts: defaultDialOptions(), + blockingpicker: newPickerWrapper(), + czData: new(channelzData), + firstResolveEvent: grpcsync.NewEvent(), + } + cc.retryThrottler.Store((*retryThrottler)(nil)) cc.ctx, cc.cancel = context.WithCancel(context.Background()) for _, opt := range opts { - opt(&cc.dopts) + opt.apply(&cc.dopts) } if channelz.IsOn() { if cc.dopts.channelzParentID != 0 { - cc.channelzID = channelz.RegisterChannel(cc, cc.dopts.channelzParentID, target) + cc.channelzID = channelz.RegisterChannel(&channelzChannel{cc}, cc.dopts.channelzParentID, target) + channelz.AddTraceEvent(cc.channelzID, &channelz.TraceEventDesc{ + Desc: "Channel Created", + Severity: channelz.CtINFO, + Parent: &channelz.TraceEventDesc{ + Desc: fmt.Sprintf("Nested Channel(id:%d) created", cc.channelzID), + Severity: channelz.CtINFO, + }, + }) } else { - cc.channelzID = channelz.RegisterChannel(cc, 0, target) + cc.channelzID = channelz.RegisterChannel(&channelzChannel{cc}, 0, target) + channelz.AddTraceEvent(cc.channelzID, &channelz.TraceEventDesc{ + Desc: "Channel Created", + Severity: channelz.CtINFO, + }) } + cc.csMgr.channelzID = cc.channelzID } if !cc.dopts.insecure { - if cc.dopts.copts.TransportCredentials == nil { + if cc.dopts.copts.TransportCredentials == nil && cc.dopts.copts.CredsBundle == nil { return nil, errNoTransportSecurity } + if cc.dopts.copts.TransportCredentials != nil && cc.dopts.copts.CredsBundle != nil { + return nil, errTransportCredsAndBundle + } } else { - if cc.dopts.copts.TransportCredentials != nil { + if cc.dopts.copts.TransportCredentials != nil || cc.dopts.copts.CredsBundle != nil { return nil, errCredentialsConflict } for _, cd := range cc.dopts.copts.PerRPCCredentials { @@ -499,7 +186,7 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn * cc.dopts.copts.Dialer = newProxyDialer( func(ctx context.Context, addr string) (net.Conn, error) { network, addr := parseDialTarget(addr) - return dialContext(ctx, network, addr) + return (&net.Dialer{}).DialContext(ctx, network, addr) }, ) } @@ -567,8 +254,8 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn * creds := cc.dopts.copts.TransportCredentials if creds != nil && creds.Info().ServerName != "" { cc.authority = creds.Info().ServerName - } else if cc.dopts.insecure && cc.dopts.copts.Authority != "" { - cc.authority = cc.dopts.copts.Authority + } else if cc.dopts.insecure && cc.dopts.authority != "" { + cc.authority = cc.dopts.authority } else { // Use endpoint from "scheme://authority/endpoint" as the default // authority for ClientConn. @@ -596,30 +283,35 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn * } cc.balancerBuildOpts = balancer.BuildOptions{ DialCreds: credsClone, + CredsBundle: cc.dopts.copts.CredsBundle, Dialer: cc.dopts.copts.Dialer, ChannelzParentID: cc.channelzID, } // Build the resolver. - cc.resolverWrapper, err = newCCResolverWrapper(cc) + rWrapper, err := newCCResolverWrapper(cc) if err != nil { return nil, fmt.Errorf("failed to build resolver: %v", err) } - // Start the resolver wrapper goroutine after resolverWrapper is created. - // - // If the goroutine is started before resolverWrapper is ready, the - // following may happen: The goroutine sends updates to cc. cc forwards - // those to balancer. Balancer creates new addrConn. addrConn fails to - // connect, and calls resolveNow(). resolveNow() tries to use the non-ready - // resolverWrapper. - cc.resolverWrapper.start() + cc.mu.Lock() + cc.resolverWrapper = rWrapper + cc.mu.Unlock() // A blocking dial blocks until the clientConn is ready. if cc.dopts.block { for { s := cc.GetState() if s == connectivity.Ready { break + } else if cc.dopts.copts.FailOnNonTempDialError && s == connectivity.TransientFailure { + if err = cc.blockingpicker.connectionError(); err != nil { + terr, ok := err.(interface { + Temporary() bool + }) + if ok && !terr.Temporary() { + return nil, err + } + } } if !cc.WaitForStateChange(ctx, s) { // ctx got timeout or canceled. @@ -637,6 +329,7 @@ type connectivityStateManager struct { mu sync.Mutex state connectivity.State notifyChan chan struct{} + channelzID int64 } // updateState updates the connectivity.State of ClientConn. @@ -652,6 +345,12 @@ func (csm *connectivityStateManager) updateState(state connectivity.State) { return } csm.state = state + if channelz.IsOn() { + channelz.AddTraceEvent(csm.channelzID, &channelz.TraceEventDesc{ + Desc: fmt.Sprintf("Channel Connectivity change to %v", state), + Severity: channelz.CtINFO, + }) + } if csm.notifyChan != nil { // There are other goroutines waiting on this channel. close(csm.notifyChan) @@ -686,26 +385,25 @@ type ClientConn struct { csMgr *connectivityStateManager balancerBuildOpts balancer.BuildOptions - resolverWrapper *ccResolverWrapper blockingpicker *pickerWrapper - mu sync.RWMutex - sc ServiceConfig - scRaw string - conns map[*addrConn]struct{} + mu sync.RWMutex + resolverWrapper *ccResolverWrapper + sc ServiceConfig + scRaw string + conns map[*addrConn]struct{} // Keepalive parameter can be updated if a GoAway is received. mkp keepalive.ClientParameters curBalancerName string preBalancerName string // previous balancer name. curAddresses []resolver.Address balancerWrapper *ccBalancerWrapper + retryThrottler atomic.Value + + firstResolveEvent *grpcsync.Event - channelzID int64 // channelz unique identification number - czmu sync.RWMutex - callsStarted int64 - callsSucceeded int64 - callsFailed int64 - lastCallStartedTime time.Time + channelzID int64 // channelz unique identification number + czData *channelzData } // WaitForStateChange waits until the connectivity.State of ClientConn changes from sourceState or @@ -749,6 +447,25 @@ func (cc *ClientConn) scWatcher() { } } +// waitForResolvedAddrs blocks until the resolver has provided addresses or the +// context expires. Returns nil unless the context expires first; otherwise +// returns a status error based on the context. +func (cc *ClientConn) waitForResolvedAddrs(ctx context.Context) error { + // This is on the RPC path, so we use a fast path to avoid the + // more-expensive "select" below after the resolver has returned once. + if cc.firstResolveEvent.HasFired() { + return nil + } + select { + case <-cc.firstResolveEvent.Done(): + return nil + case <-ctx.Done(): + return status.FromContextError(ctx.Err()).Err() + case <-cc.ctx.Done(): + return ErrClientConnClosing + } +} + func (cc *ClientConn) handleResolvedAddrs(addrs []resolver.Address, err error) { cc.mu.Lock() defer cc.mu.Unlock() @@ -762,6 +479,7 @@ func (cc *ClientConn) handleResolvedAddrs(addrs []resolver.Address, err error) { } cc.curAddresses = addrs + cc.firstResolveEvent.Fire() if cc.dopts.balancerBuilder == nil { // Only look at balancer types and switch balancer if balancer dial @@ -830,14 +548,28 @@ func (cc *ClientConn) switchBalancer(name string) { if cc.balancerWrapper != nil { cc.balancerWrapper.close() } - // Clear all stickiness state. - cc.blockingpicker.clearStickinessState() builder := balancer.Get(name) + // TODO(yuxuanli): If user send a service config that does not contain a valid balancer name, should + // we reuse previous one? + if channelz.IsOn() { + if builder == nil { + channelz.AddTraceEvent(cc.channelzID, &channelz.TraceEventDesc{ + Desc: fmt.Sprintf("Channel switches to new LB policy %q due to fallback from invalid balancer name", PickFirstBalancerName), + Severity: channelz.CtWarning, + }) + } else { + channelz.AddTraceEvent(cc.channelzID, &channelz.TraceEventDesc{ + Desc: fmt.Sprintf("Channel switches to new LB policy %q", name), + Severity: channelz.CtINFO, + }) + } + } if builder == nil { grpclog.Infof("failed to get balancer builder for: %v, using pick_first instead", name) builder = newPickfirstBuilder() } + cc.preBalancerName = cc.curBalancerName cc.curBalancerName = builder.Name() cc.balancerWrapper = newCCBalancerWrapper(cc, builder, cc.balancerBuildOpts) @@ -858,11 +590,15 @@ func (cc *ClientConn) handleSubConnStateChange(sc balancer.SubConn, s connectivi // newAddrConn creates an addrConn for addrs and adds it to cc.conns. // // Caller needs to make sure len(addrs) > 0. -func (cc *ClientConn) newAddrConn(addrs []resolver.Address) (*addrConn, error) { +func (cc *ClientConn) newAddrConn(addrs []resolver.Address, opts balancer.NewSubConnOptions) (*addrConn, error) { ac := &addrConn{ - cc: cc, - addrs: addrs, - dopts: cc.dopts, + cc: cc, + addrs: addrs, + scopts: opts, + dopts: cc.dopts, + czData: new(channelzData), + successfulHandshake: true, // make the first nextAddr() call _not_ move addrIdx up by 1 + resetBackoff: make(chan struct{}), } ac.ctx, ac.cancel = context.WithCancel(cc.ctx) // Track ac in cc. This needs to be done before any getTransport(...) is called. @@ -873,6 +609,14 @@ func (cc *ClientConn) newAddrConn(addrs []resolver.Address) (*addrConn, error) { } if channelz.IsOn() { ac.channelzID = channelz.RegisterSubChannel(ac, cc.channelzID, "") + channelz.AddTraceEvent(ac.channelzID, &channelz.TraceEventDesc{ + Desc: "Subchannel Created", + Severity: channelz.CtINFO, + Parent: &channelz.TraceEventDesc{ + Desc: fmt.Sprintf("Subchannel(id:%d) created", ac.channelzID), + Severity: channelz.CtINFO, + }, + }) } cc.conns[ac] = struct{}{} cc.mu.Unlock() @@ -892,47 +636,39 @@ func (cc *ClientConn) removeAddrConn(ac *addrConn, err error) { ac.tearDown(err) } -// ChannelzMetric returns ChannelInternalMetric of current ClientConn. -// This is an EXPERIMENTAL API. -func (cc *ClientConn) ChannelzMetric() *channelz.ChannelInternalMetric { - state := cc.GetState() - cc.czmu.RLock() - defer cc.czmu.RUnlock() +func (cc *ClientConn) channelzMetric() *channelz.ChannelInternalMetric { return &channelz.ChannelInternalMetric{ - State: state, + State: cc.GetState(), Target: cc.target, - CallsStarted: cc.callsStarted, - CallsSucceeded: cc.callsSucceeded, - CallsFailed: cc.callsFailed, - LastCallStartedTimestamp: cc.lastCallStartedTime, + CallsStarted: atomic.LoadInt64(&cc.czData.callsStarted), + CallsSucceeded: atomic.LoadInt64(&cc.czData.callsSucceeded), + CallsFailed: atomic.LoadInt64(&cc.czData.callsFailed), + LastCallStartedTimestamp: time.Unix(0, atomic.LoadInt64(&cc.czData.lastCallStartedTime)), } } +// Target returns the target string of the ClientConn. +// This is an EXPERIMENTAL API. +func (cc *ClientConn) Target() string { + return cc.target +} + func (cc *ClientConn) incrCallsStarted() { - cc.czmu.Lock() - cc.callsStarted++ - // TODO(yuxuanli): will make this a time.Time pointer improve performance? - cc.lastCallStartedTime = time.Now() - cc.czmu.Unlock() + atomic.AddInt64(&cc.czData.callsStarted, 1) + atomic.StoreInt64(&cc.czData.lastCallStartedTime, time.Now().UnixNano()) } func (cc *ClientConn) incrCallsSucceeded() { - cc.czmu.Lock() - cc.callsSucceeded++ - cc.czmu.Unlock() + atomic.AddInt64(&cc.czData.callsSucceeded, 1) } func (cc *ClientConn) incrCallsFailed() { - cc.czmu.Lock() - cc.callsFailed++ - cc.czmu.Unlock() + atomic.AddInt64(&cc.czData.callsFailed, 1) } -// connect starts to creating transport and also starts the transport monitor -// goroutine for this ac. +// connect starts creating a transport. // It does nothing if the ac is not IDLE. // TODO(bar) Move this to the addrConn section. -// This was part of resetAddrConn, keep it here to make the diff look clean. func (ac *addrConn) connect() error { ac.mu.Lock() if ac.state == connectivity.Shutdown { @@ -943,22 +679,12 @@ func (ac *addrConn) connect() error { ac.mu.Unlock() return nil } - ac.state = connectivity.Connecting + ac.updateConnectivityState(connectivity.Connecting) ac.cc.handleSubConnStateChange(ac.acbw, ac.state) ac.mu.Unlock() // Start a goroutine connecting to the server asynchronously. - go func() { - if err := ac.resetTransport(); err != nil { - grpclog.Warningf("Failed to dial %s: %v; please retry.", ac.addrs[0].Addr, err) - if err != errConnClosing { - // Keep this ac in cc.conns, to get the reason it's torn down. - ac.tearDown(err) - } - return - } - ac.transportMonitor() - }() + go ac.resetTransport(false) return nil } @@ -987,7 +713,7 @@ func (ac *addrConn) tryUpdateAddrs(addrs []resolver.Address) bool { grpclog.Infof("addrConn: tryUpdateAddrs curAddrFound: %v", curAddrFound) if curAddrFound { ac.addrs = addrs - ac.reconnectIdx = 0 // Start reconnecting from beginning in the new list. + ac.addrIdx = 0 // Start reconnecting from beginning in the new list. } return curAddrFound @@ -1012,8 +738,18 @@ func (cc *ClientConn) GetMethodConfig(method string) MethodConfig { return m } -func (cc *ClientConn) getTransport(ctx context.Context, failfast bool) (transport.ClientTransport, func(balancer.DoneInfo), error) { - t, done, err := cc.blockingpicker.pick(ctx, failfast, balancer.PickOptions{}) +func (cc *ClientConn) healthCheckConfig() *healthCheckConfig { + cc.mu.RLock() + defer cc.mu.RUnlock() + return cc.sc.healthCheckConfig +} + +func (cc *ClientConn) getTransport(ctx context.Context, failfast bool, method string) (transport.ClientTransport, func(balancer.DoneInfo), error) { + hdr, _ := metadata.FromOutgoingContext(ctx) + t, done, err := cc.blockingpicker.pick(ctx, failfast, balancer.PickOptions{ + FullMethodName: method, + Header: hdr, + }) if err != nil { return nil, nil, toRPCErr(err) } @@ -1026,13 +762,44 @@ func (cc *ClientConn) handleServiceConfig(js string) error { if cc.dopts.disableServiceConfig { return nil } + if cc.scRaw == js { + return nil + } + if channelz.IsOn() { + channelz.AddTraceEvent(cc.channelzID, &channelz.TraceEventDesc{ + // The special formatting of \"%s\" instead of %q is to provide nice printing of service config + // for human consumption. + Desc: fmt.Sprintf("Channel has a new service config \"%s\"", js), + Severity: channelz.CtINFO, + }) + } sc, err := parseServiceConfig(js) if err != nil { return err } cc.mu.Lock() + // Check if the ClientConn is already closed. Some fields (e.g. + // balancerWrapper) are set to nil when closing the ClientConn, and could + // cause nil pointer panic if we don't have this check. + if cc.conns == nil { + cc.mu.Unlock() + return nil + } cc.scRaw = js cc.sc = sc + + if sc.retryThrottling != nil { + newThrottler := &retryThrottler{ + tokens: sc.retryThrottling.MaxTokens, + max: sc.retryThrottling.MaxTokens, + thresh: sc.retryThrottling.MaxTokens / 2, + ratio: sc.retryThrottling.TokenRatio, + } + cc.retryThrottler.Store(newThrottler) + } else { + cc.retryThrottler.Store((*retryThrottler)(nil)) + } + if sc.LB != nil && *sc.LB != grpclbName { // "grpclb" is not a valid balancer option in service config. if cc.curBalancerName == grpclbName { // If current balancer is grpclb, there's at least one grpclb @@ -1047,17 +814,6 @@ func (cc *ClientConn) handleServiceConfig(js string) error { } } - if envConfigStickinessOn { - var newStickinessMDKey string - if sc.stickinessMetadataKey != nil && *sc.stickinessMetadataKey != "" { - newStickinessMDKey = *sc.stickinessMetadataKey - } - // newStickinessMDKey is "" if one of the following happens: - // - stickinessMetadataKey is set to "" - // - stickinessMetadataKey field doesn't exist in service config - cc.blockingpicker.updateStickinessMDKey(strings.ToLower(newStickinessMDKey)) - } - cc.mu.Unlock() return nil } @@ -1072,6 +828,24 @@ func (cc *ClientConn) resolveNow(o resolver.ResolveNowOption) { go r.resolveNow(o) } +// ResetConnectBackoff wakes up all subchannels in transient failure and causes +// them to attempt another connection immediately. It also resets the backoff +// times used for subsequent attempts regardless of the current state. +// +// In general, this function should not be used. Typical service or network +// outages result in a reasonable client reconnection strategy by default. +// However, if a previously unavailable network becomes available, this may be +// used to trigger an immediate reconnect. +// +// This API is EXPERIMENTAL. +func (cc *ClientConn) ResetConnectBackoff() { + cc.mu.Lock() + defer cc.mu.Unlock() + for ac := range cc.conns { + ac.resetConnectBackoff() + } +} + // Close tears down the ClientConn and all underlying connections. func (cc *ClientConn) Close() error { defer cc.cancel() @@ -1104,6 +878,19 @@ func (cc *ClientConn) Close() error { ac.tearDown(ErrClientConnClosing) } if channelz.IsOn() { + ted := &channelz.TraceEventDesc{ + Desc: "Channel Deleted", + Severity: channelz.CtINFO, + } + if cc.dopts.channelzParentID != 0 { + ted.Parent = &channelz.TraceEventDesc{ + Desc: fmt.Sprintf("Nested channel(id:%d) deleted", cc.channelzID), + Severity: channelz.CtINFO, + } + } + channelz.AddTraceEvent(cc.channelzID, ted) + // TraceEvent needs to be called before RemoveEntry, as TraceEvent may add trace reference to + // the entity beng deleted, and thus prevent it from being deleted right away. channelz.RemoveEntry(cc.channelzID) } return nil @@ -1115,37 +902,53 @@ type addrConn struct { cancel context.CancelFunc cc *ClientConn - addrs []resolver.Address dopts dialOptions - events trace.EventLog acbw balancer.SubConn + scopts balancer.NewSubConnOptions + + // transport is set when there's a viable transport (note: ac state may not be READY as LB channel + // health checking may require server to report healthy to set ac to READY), and is reset + // to nil when the current transport should no longer be used to create a stream (e.g. after GoAway + // is received, transport is closed, ac has been torn down). + transport transport.ClientTransport // The current transport. + + mu sync.Mutex + addrIdx int // The index in addrs list to start reconnecting from. + curAddr resolver.Address // The current address. + addrs []resolver.Address // All addresses that the resolver resolved to. - mu sync.Mutex - curAddr resolver.Address - reconnectIdx int // The index in addrs list to start reconnecting from. - state connectivity.State - // ready is closed and becomes nil when a new transport is up or failed - // due to timeout. - ready chan struct{} - transport transport.ClientTransport + // Use updateConnectivityState for updating addrConn's connectivity state. + state connectivity.State - // The reason this addrConn is torn down. - tearDownErr error + tearDownErr error // The reason this addrConn is torn down. - connectRetryNum int + backoffIdx int // backoffDeadline is the time until which resetTransport needs to - // wait before increasing connectRetryNum count. + // wait before increasing backoffIdx count. backoffDeadline time.Time // connectDeadline is the time by which all connection // negotiations must complete. connectDeadline time.Time - channelzID int64 // channelz unique identification number - czmu sync.RWMutex - callsStarted int64 - callsSucceeded int64 - callsFailed int64 - lastCallStartedTime time.Time + resetBackoff chan struct{} + + channelzID int64 // channelz unique identification number + czData *channelzData + + successfulHandshake bool + + healthCheckEnabled bool +} + +// Note: this requires a lock on ac.mu. +func (ac *addrConn) updateConnectivityState(s connectivity.State) { + ac.state = s + if channelz.IsOn() { + channelz.AddTraceEvent(ac.channelzID, &channelz.TraceEventDesc{ + Desc: fmt.Sprintf("Subchannel Connectivity change to %v", s), + Severity: channelz.CtINFO, + }) + } } // adjustParams updates parameters used to create transports upon @@ -1162,329 +965,393 @@ func (ac *addrConn) adjustParams(r transport.GoAwayReason) { } } -// printf records an event in ac's event log, unless ac has been closed. -// REQUIRES ac.mu is held. -func (ac *addrConn) printf(format string, a ...interface{}) { - if ac.events != nil { - ac.events.Printf(format, a...) - } -} +// resetTransport makes sure that a healthy ac.transport exists. +// +// The transport will close itself when it encounters an error, or on GOAWAY, or on deadline waiting for handshake, or +// when the clientconn is closed. Each iteration creating a new transport will try a different address that the balancer +// assigned to the addrConn, until it has tried all addresses. Once it has tried all addresses, it will re-resolve to +// get a new address list. If an error is received, the list is re-resolved and the next reset attempt will try from the +// beginning. This method has backoff built in. The backoff amount starts at 0 and increases each time resolution occurs +// (addresses are exhausted). The backoff amount is reset to 0 each time a handshake is received. +// +// If the DialOption WithWaitForHandshake was set, resetTransport returns successfully only after handshake is received. +func (ac *addrConn) resetTransport(resolveNow bool) { + for { + // If this is the first in a line of resets, we want to resolve immediately. The only other time we + // want to reset is if we have tried all the addresses handed to us. + if resolveNow { + ac.mu.Lock() + ac.cc.resolveNow(resolver.ResolveNowOption{}) + ac.mu.Unlock() + } -// errorf records an error in ac's event log, unless ac has been closed. -// REQUIRES ac.mu is held. -func (ac *addrConn) errorf(format string, a ...interface{}) { - if ac.events != nil { - ac.events.Errorf(format, a...) - } -} + ac.mu.Lock() + if ac.state == connectivity.Shutdown { + ac.mu.Unlock() + return + } -// resetTransport recreates a transport to the address for ac. The old -// transport will close itself on error or when the clientconn is closed. -// The created transport must receive initial settings frame from the server. -// In case that doesn't happen, transportMonitor will kill the newly created -// transport after connectDeadline has expired. -// In case there was an error on the transport before the settings frame was -// received, resetTransport resumes connecting to backends after the one that -// was previously connected to. In case end of the list is reached, resetTransport -// backs off until the original deadline. -// If the DialOption WithWaitForHandshake was set, resetTrasport returns -// successfully only after server settings are received. -// -// TODO(bar) make sure all state transitions are valid. -func (ac *addrConn) resetTransport() error { - ac.mu.Lock() - if ac.state == connectivity.Shutdown { + // The transport that was used before is no longer viable. + ac.transport = nil + // If the connection is READY, a failure must have occurred. + // Otherwise, we'll consider this is a transient failure when: + // We've exhausted all addresses + // We're in CONNECTING + // And it's not the very first addr to try TODO(deklerk) find a better way to do this than checking ac.successfulHandshake + if ac.state == connectivity.Ready || (ac.addrIdx == len(ac.addrs)-1 && ac.state == connectivity.Connecting && !ac.successfulHandshake) { + ac.updateConnectivityState(connectivity.TransientFailure) + ac.cc.handleSubConnStateChange(ac.acbw, ac.state) + } + ac.transport = nil ac.mu.Unlock() - return errConnClosing - } - if ac.ready != nil { - close(ac.ready) - ac.ready = nil - } - ac.transport = nil - ridx := ac.reconnectIdx - ac.mu.Unlock() - ac.cc.mu.RLock() - ac.dopts.copts.KeepaliveParams = ac.cc.mkp - ac.cc.mu.RUnlock() - var backoffDeadline, connectDeadline time.Time - for connectRetryNum := 0; ; connectRetryNum++ { + + if err := ac.nextAddr(); err != nil { + return + } + ac.mu.Lock() - if ac.backoffDeadline.IsZero() { - // This means either a successful HTTP2 connection was established - // or this is the first time this addrConn is trying to establish a - // connection. - backoffFor := ac.dopts.bs.Backoff(connectRetryNum) // time.Duration. - // This will be the duration that dial gets to finish. - dialDuration := getMinConnectTimeout() - if backoffFor > dialDuration { - // Give dial more time as we keep failing to connect. - dialDuration = backoffFor - } - start := time.Now() - backoffDeadline = start.Add(backoffFor) - connectDeadline = start.Add(dialDuration) - ridx = 0 // Start connecting from the beginning. - } else { - // Continue trying to connect with the same deadlines. - connectRetryNum = ac.connectRetryNum - backoffDeadline = ac.backoffDeadline - connectDeadline = ac.connectDeadline - ac.backoffDeadline = time.Time{} - ac.connectDeadline = time.Time{} - ac.connectRetryNum = 0 + if ac.state == connectivity.Shutdown { + ac.mu.Unlock() + return + } + + backoffIdx := ac.backoffIdx + backoffFor := ac.dopts.bs.Backoff(backoffIdx) + + // This will be the duration that dial gets to finish. + dialDuration := getMinConnectTimeout() + if backoffFor > dialDuration { + // Give dial more time as we keep failing to connect. + dialDuration = backoffFor } + start := time.Now() + connectDeadline := start.Add(dialDuration) + ac.backoffDeadline = start.Add(backoffFor) + ac.connectDeadline = connectDeadline + + ac.mu.Unlock() + + ac.cc.mu.RLock() + ac.dopts.copts.KeepaliveParams = ac.cc.mkp + ac.cc.mu.RUnlock() + + ac.mu.Lock() + if ac.state == connectivity.Shutdown { ac.mu.Unlock() - return errConnClosing + return } - ac.printf("connecting") + if ac.state != connectivity.Connecting { - ac.state = connectivity.Connecting + ac.updateConnectivityState(connectivity.Connecting) ac.cc.handleSubConnStateChange(ac.acbw, ac.state) } - // copy ac.addrs in case of race - addrsIter := make([]resolver.Address, len(ac.addrs)) - copy(addrsIter, ac.addrs) + + addr := ac.addrs[ac.addrIdx] copts := ac.dopts.copts + if ac.scopts.CredsBundle != nil { + copts.CredsBundle = ac.scopts.CredsBundle + } ac.mu.Unlock() - connected, err := ac.createTransport(connectRetryNum, ridx, backoffDeadline, connectDeadline, addrsIter, copts) - if err != nil { - return err + + if channelz.IsOn() { + channelz.AddTraceEvent(ac.channelzID, &channelz.TraceEventDesc{ + Desc: fmt.Sprintf("Subchannel picks a new address %q to connect", addr.Addr), + Severity: channelz.CtINFO, + }) } - if connected { - return nil + + if err := ac.createTransport(backoffIdx, addr, copts, connectDeadline); err != nil { + continue } + + return } } // createTransport creates a connection to one of the backends in addrs. -// It returns true if a connection was established. -func (ac *addrConn) createTransport(connectRetryNum, ridx int, backoffDeadline, connectDeadline time.Time, addrs []resolver.Address, copts transport.ConnectOptions) (bool, error) { - for i := ridx; i < len(addrs); i++ { - addr := addrs[i] - target := transport.TargetInfo{ - Addr: addr.Addr, - Metadata: addr.Metadata, - Authority: ac.cc.authority, +func (ac *addrConn) createTransport(backoffNum int, addr resolver.Address, copts transport.ConnectOptions, connectDeadline time.Time) error { + oneReset := sync.Once{} + skipReset := make(chan struct{}) + allowedToReset := make(chan struct{}) + prefaceReceived := make(chan struct{}) + onCloseCalled := make(chan struct{}) + + var prefaceMu sync.Mutex + var serverPrefaceReceived bool + var clientPrefaceWrote bool + + hcCtx, hcCancel := context.WithCancel(ac.ctx) + + onGoAway := func(r transport.GoAwayReason) { + hcCancel() + ac.mu.Lock() + ac.adjustParams(r) + ac.mu.Unlock() + select { + case <-skipReset: // The outer resetTransport loop will handle reconnection. + return + case <-allowedToReset: // We're in the clear to reset. + go oneReset.Do(func() { ac.resetTransport(false) }) } - done := make(chan struct{}) - onPrefaceReceipt := func() { - ac.mu.Lock() - close(done) - if !ac.backoffDeadline.IsZero() { - // If we haven't already started reconnecting to - // other backends. - // Note, this can happen when writer notices an error - // and triggers resetTransport while at the same time - // reader receives the preface and invokes this closure. - ac.backoffDeadline = time.Time{} - ac.connectDeadline = time.Time{} - ac.connectRetryNum = 0 - } - ac.mu.Unlock() + } + + prefaceTimer := time.NewTimer(connectDeadline.Sub(time.Now())) + + onClose := func() { + hcCancel() + close(onCloseCalled) + prefaceTimer.Stop() + + select { + case <-skipReset: // The outer resetTransport loop will handle reconnection. + return + case <-allowedToReset: // We're in the clear to reset. + oneReset.Do(func() { ac.resetTransport(false) }) } - // Do not cancel in the success path because of - // this issue in Go1.6: https://github.com/golang/go/issues/15078. - connectCtx, cancel := context.WithDeadline(ac.ctx, connectDeadline) - if channelz.IsOn() { - copts.ChannelzParentID = ac.channelzID + } + + target := transport.TargetInfo{ + Addr: addr.Addr, + Metadata: addr.Metadata, + Authority: ac.cc.authority, + } + + onPrefaceReceipt := func() { + close(prefaceReceived) + prefaceTimer.Stop() + + // TODO(deklerk): optimization; does anyone else actually use this lock? maybe we can just remove it for this scope + ac.mu.Lock() + + prefaceMu.Lock() + serverPrefaceReceived = true + if clientPrefaceWrote { + ac.successfulHandshake = true } - newTr, err := transport.NewClientTransport(connectCtx, ac.cc.ctx, target, copts, onPrefaceReceipt) - if err != nil { - cancel() - ac.cc.blockingpicker.updateConnectionError(err) - ac.mu.Lock() - if ac.state == connectivity.Shutdown { - // ac.tearDown(...) has been invoked. - ac.mu.Unlock() - return false, errConnClosing - } - ac.mu.Unlock() - grpclog.Warningf("grpc: addrConn.createTransport failed to connect to %v. Err :%v. Reconnecting...", addr, err) - continue + prefaceMu.Unlock() + + ac.mu.Unlock() + } + + connectCtx, cancel := context.WithDeadline(ac.ctx, connectDeadline) + defer cancel() + if channelz.IsOn() { + copts.ChannelzParentID = ac.channelzID + } + + newTr, err := transport.NewClientTransport(connectCtx, ac.cc.ctx, target, copts, onPrefaceReceipt, onGoAway, onClose) + + if err == nil { + prefaceMu.Lock() + clientPrefaceWrote = true + if serverPrefaceReceived || ac.dopts.reqHandshake == envconfig.RequireHandshakeOff { + ac.successfulHandshake = true } - if ac.dopts.waitForHandshake { + prefaceMu.Unlock() + + if ac.dopts.reqHandshake == envconfig.RequireHandshakeOn { select { - case <-done: - case <-connectCtx.Done(): - // Didn't receive server preface, must kill this new transport now. - grpclog.Warningf("grpc: addrConn.createTransport failed to receive server preface before deadline.") + case <-prefaceTimer.C: + // We didn't get the preface in time. newTr.Close() - break - case <-ac.ctx.Done(): + err = errors.New("timed out waiting for server handshake") + case <-prefaceReceived: + // We got the preface - huzzah! things are good. + case <-onCloseCalled: + // The transport has already closed - noop. + close(allowedToReset) + return nil } + } else if ac.dopts.reqHandshake == envconfig.RequireHandshakeHybrid { + go func() { + select { + case <-prefaceTimer.C: + // We didn't get the preface in time. + newTr.Close() + case <-prefaceReceived: + // We got the preface just in the nick of time - huzzah! + case <-onCloseCalled: + // The transport has already closed - noop. + } + }() } + } + + if err != nil { + // newTr is either nil, or closed. + ac.cc.blockingpicker.updateConnectionError(err) ac.mu.Lock() if ac.state == connectivity.Shutdown { + // ac.tearDown(...) has been invoked. ac.mu.Unlock() - // ac.tearDonn(...) has been invoked. - newTr.Close() - return false, errConnClosing - } - ac.printf("ready") - ac.state = connectivity.Ready - ac.cc.handleSubConnStateChange(ac.acbw, ac.state) - ac.transport = newTr - ac.curAddr = addr - if ac.ready != nil { - close(ac.ready) - ac.ready = nil - } - select { - case <-done: - // If the server has responded back with preface already, - // don't set the reconnect parameters. - default: - ac.connectRetryNum = connectRetryNum - ac.backoffDeadline = backoffDeadline - ac.connectDeadline = connectDeadline - ac.reconnectIdx = i + 1 // Start reconnecting from the next backend in the list. + + // We don't want to reset during this close because we prefer to kick out of this function and let the loop + // in resetTransport take care of reconnecting. + close(skipReset) + + return errConnClosing } ac.mu.Unlock() - return true, nil + grpclog.Warningf("grpc: addrConn.createTransport failed to connect to %v. Err :%v. Reconnecting...", addr, err) + + // We don't want to reset during this close because we prefer to kick out of this function and let the loop + // in resetTransport take care of reconnecting. + close(skipReset) + + return err } + + // Now there is a viable transport to be use, so set ac.transport to reflect the new viable transport. ac.mu.Lock() if ac.state == connectivity.Shutdown { ac.mu.Unlock() - return false, errConnClosing - } - ac.state = connectivity.TransientFailure - ac.cc.handleSubConnStateChange(ac.acbw, ac.state) - ac.cc.resolveNow(resolver.ResolveNowOption{}) - if ac.ready != nil { - close(ac.ready) - ac.ready = nil + close(skipReset) + newTr.Close() + return nil } + ac.transport = newTr ac.mu.Unlock() - timer := time.NewTimer(backoffDeadline.Sub(time.Now())) - select { - case <-timer.C: - case <-ac.ctx.Done(): - timer.Stop() - return false, ac.ctx.Err() - } - return false, nil -} -// Run in a goroutine to track the error in transport and create the -// new transport if an error happens. It returns when the channel is closing. -func (ac *addrConn) transportMonitor() { - for { - var timer *time.Timer - var cdeadline <-chan time.Time - ac.mu.Lock() - t := ac.transport - if !ac.connectDeadline.IsZero() { - timer = time.NewTimer(ac.connectDeadline.Sub(time.Now())) - cdeadline = timer.C + healthCheckConfig := ac.cc.healthCheckConfig() + // LB channel health checking is only enabled when all the four requirements below are met: + // 1. it is not disabled by the user with the WithDisableHealthCheck DialOption, + // 2. the internal.HealthCheckFunc is set by importing the grpc/healthcheck package, + // 3. a service config with non-empty healthCheckConfig field is provided, + // 4. the current load balancer allows it. + if !ac.cc.dopts.disableHealthCheck && healthCheckConfig != nil && ac.scopts.HealthCheckEnabled { + if internal.HealthCheckFunc != nil { + go ac.startHealthCheck(hcCtx, newTr, addr, healthCheckConfig.ServiceName) + close(allowedToReset) + return nil } + // TODO: add a link to the health check doc in the error message. + grpclog.Error("the client side LB channel health check function has not been set.") + } + + // No LB channel health check case + ac.mu.Lock() + + if ac.state == connectivity.Shutdown { ac.mu.Unlock() - // Block until we receive a goaway or an error occurs. - select { - case <-t.GoAway(): - done := t.Error() - cleanup := t.Close - // Since this transport will be orphaned (won't have a transportMonitor) - // we need to launch a goroutine to keep track of clientConn.Close() - // happening since it might not be noticed by any other goroutine for a while. - go func() { - <-done - cleanup() - }() - case <-t.Error(): - // In case this is triggered because clientConn.Close() - // was called, we want to immeditately close the transport - // since no other goroutine might notice it for a while. - t.Close() - case <-cdeadline: - ac.mu.Lock() - // This implies that client received server preface. - if ac.backoffDeadline.IsZero() { - ac.mu.Unlock() - continue - } - ac.mu.Unlock() - timer = nil - // No server preface received until deadline. - // Kill the connection. - grpclog.Warningf("grpc: addrConn.transportMonitor didn't get server preface after waiting. Closing the new transport now.") - t.Close() - } - if timer != nil { - timer.Stop() - } - // If a GoAway happened, regardless of error, adjust our keepalive - // parameters as appropriate. - select { - case <-t.GoAway(): - ac.adjustParams(t.GetGoAwayReason()) - default: - } + + // unblock onGoAway/onClose callback. + close(skipReset) + return errConnClosing + } + + ac.updateConnectivityState(connectivity.Ready) + ac.cc.handleSubConnStateChange(ac.acbw, ac.state) + ac.curAddr = addr + + ac.mu.Unlock() + + // Ok, _now_ we will finally let the transport reset if it encounters a closable error. Without this, the reader + // goroutine failing races with all the code in this method that sets the connection to "ready". + close(allowedToReset) + return nil +} + +func (ac *addrConn) startHealthCheck(ctx context.Context, newTr transport.ClientTransport, addr resolver.Address, serviceName string) { + // Set up the health check helper functions + newStream := func() (interface{}, error) { + return ac.newClientStream(ctx, &StreamDesc{ServerStreams: true}, "/grpc.health.v1.Health/Watch", newTr) + } + firstReady := true + reportHealth := func(ok bool) { ac.mu.Lock() - if ac.state == connectivity.Shutdown { - ac.mu.Unlock() + defer ac.mu.Unlock() + if ac.transport != newTr { return } - // Set connectivity state to TransientFailure before calling - // resetTransport. Transition READY->CONNECTING is not valid. - ac.state = connectivity.TransientFailure - ac.cc.handleSubConnStateChange(ac.acbw, ac.state) - ac.cc.resolveNow(resolver.ResolveNowOption{}) - ac.curAddr = resolver.Address{} - ac.mu.Unlock() - if err := ac.resetTransport(); err != nil { - ac.mu.Lock() - ac.printf("transport exiting: %v", err) - ac.mu.Unlock() - grpclog.Warningf("grpc: addrConn.transportMonitor exits due to: %v", err) - if err != errConnClosing { - // Keep this ac in cc.conns, to get the reason it's torn down. - ac.tearDown(err) + if ok { + if firstReady { + firstReady = false + ac.curAddr = addr + } + if ac.state != connectivity.Ready { + ac.updateConnectivityState(connectivity.Ready) + ac.cc.handleSubConnStateChange(ac.acbw, ac.state) + } + } else { + if ac.state != connectivity.TransientFailure { + ac.updateConnectivityState(connectivity.TransientFailure) + ac.cc.handleSubConnStateChange(ac.acbw, ac.state) } - return } } -} -// wait blocks until i) the new transport is up or ii) ctx is done or iii) ac is closed or -// iv) transport is in connectivity.TransientFailure and there is a balancer/failfast is true. -func (ac *addrConn) wait(ctx context.Context, hasBalancer, failfast bool) (transport.ClientTransport, error) { - for { - ac.mu.Lock() - switch { - case ac.state == connectivity.Shutdown: - if failfast || !hasBalancer { - // RPC is failfast or balancer is nil. This RPC should fail with ac.tearDownErr. - err := ac.tearDownErr - ac.mu.Unlock() - return nil, err - } - ac.mu.Unlock() - return nil, errConnClosing - case ac.state == connectivity.Ready: - ct := ac.transport - ac.mu.Unlock() - return ct, nil - case ac.state == connectivity.TransientFailure: - if failfast || hasBalancer { - ac.mu.Unlock() - return nil, errConnUnavailable + err := internal.HealthCheckFunc(ctx, newStream, reportHealth, serviceName) + if err != nil { + if status.Code(err) == codes.Unimplemented { + if channelz.IsOn() { + channelz.AddTraceEvent(ac.channelzID, &channelz.TraceEventDesc{ + Desc: "Subchannel health check is unimplemented at server side, thus health check is disabled", + Severity: channelz.CtError, + }) } + grpclog.Error("Subchannel health check is unimplemented at server side, thus health check is disabled") + } else { + grpclog.Errorf("HealthCheckFunc exits with unexpected error %v", err) } - ready := ac.ready - if ready == nil { - ready = make(chan struct{}) - ac.ready = ready - } + } +} + +// nextAddr increments the addrIdx if there are more addresses to try. If +// there are no more addrs to try it will re-resolve, set addrIdx to 0, and +// increment the backoffIdx. +// +// nextAddr must be called without ac.mu being held. +func (ac *addrConn) nextAddr() error { + ac.mu.Lock() + + // If a handshake has been observed, we want the next usage to start at + // index 0 immediately. + if ac.successfulHandshake { + ac.successfulHandshake = false + ac.backoffDeadline = time.Time{} + ac.connectDeadline = time.Time{} + ac.addrIdx = 0 + ac.backoffIdx = 0 ac.mu.Unlock() - select { - case <-ctx.Done(): - return nil, toRPCErr(ctx.Err()) - // Wait until the new transport is ready or failed. - case <-ready: - } + return nil + } + + if ac.addrIdx < len(ac.addrs)-1 { + ac.addrIdx++ + ac.mu.Unlock() + return nil + } + + ac.addrIdx = 0 + ac.backoffIdx++ + + if ac.state == connectivity.Shutdown { + ac.mu.Unlock() + return errConnClosing + } + ac.cc.resolveNow(resolver.ResolveNowOption{}) + backoffDeadline := ac.backoffDeadline + b := ac.resetBackoff + ac.mu.Unlock() + timer := time.NewTimer(backoffDeadline.Sub(time.Now())) + select { + case <-timer.C: + case <-b: + timer.Stop() + case <-ac.ctx.Done(): + timer.Stop() + return ac.ctx.Err() } + return nil +} + +func (ac *addrConn) resetConnectBackoff() { + ac.mu.Lock() + close(ac.resetBackoff) + ac.backoffIdx = 0 + ac.resetBackoff = make(chan struct{}) + ac.mu.Unlock() } // getReadyTransport returns the transport if ac's state is READY. @@ -1492,7 +1359,7 @@ func (ac *addrConn) wait(ctx context.Context, hasBalancer, failfast bool) (trans // If ac's state is IDLE, it will trigger ac to connect. func (ac *addrConn) getReadyTransport() (transport.ClientTransport, bool) { ac.mu.Lock() - if ac.state == connectivity.Ready { + if ac.state == connectivity.Ready && ac.transport != nil { t := ac.transport ac.mu.Unlock() return t, true @@ -1515,34 +1382,44 @@ func (ac *addrConn) getReadyTransport() (transport.ClientTransport, bool) { // tight loop. // tearDown doesn't remove ac from ac.cc.conns. func (ac *addrConn) tearDown(err error) { - ac.cancel() ac.mu.Lock() - defer ac.mu.Unlock() if ac.state == connectivity.Shutdown { + ac.mu.Unlock() return } + curTr := ac.transport + ac.transport = nil + // We have to set the state to Shutdown before anything else to prevent races + // between setting the state and logic that waits on context cancelation / etc. + ac.updateConnectivityState(connectivity.Shutdown) + ac.cancel() + ac.tearDownErr = err + ac.cc.handleSubConnStateChange(ac.acbw, ac.state) ac.curAddr = resolver.Address{} - if err == errConnDrain && ac.transport != nil { + if err == errConnDrain && curTr != nil { // GracefulClose(...) may be executed multiple times when // i) receiving multiple GoAway frames from the server; or // ii) there are concurrent name resolver/Balancer triggered // address removal and GoAway. - ac.transport.GracefulClose() - } - ac.state = connectivity.Shutdown - ac.tearDownErr = err - ac.cc.handleSubConnStateChange(ac.acbw, ac.state) - if ac.events != nil { - ac.events.Finish() - ac.events = nil - } - if ac.ready != nil { - close(ac.ready) - ac.ready = nil + // We have to unlock and re-lock here because GracefulClose => Close => onClose, which requires locking ac.mu. + ac.mu.Unlock() + curTr.GracefulClose() + ac.mu.Lock() } if channelz.IsOn() { + channelz.AddTraceEvent(ac.channelzID, &channelz.TraceEventDesc{ + Desc: "Subchannel Deleted", + Severity: channelz.CtINFO, + Parent: &channelz.TraceEventDesc{ + Desc: fmt.Sprintf("Subchanel(id:%d) deleted", ac.channelzID), + Severity: channelz.CtINFO, + }, + }) + // TraceEvent needs to be called before RemoveEntry, as TraceEvent may add trace reference to + // the entity beng deleted, and thus prevent it from being deleted right away. channelz.RemoveEntry(ac.channelzID) } + ac.mu.Unlock() } func (ac *addrConn) getState() connectivity.State { @@ -1551,47 +1428,76 @@ func (ac *addrConn) getState() connectivity.State { return ac.state } -func (ac *addrConn) getCurAddr() (ret resolver.Address) { - ac.mu.Lock() - ret = ac.curAddr - ac.mu.Unlock() - return -} - func (ac *addrConn) ChannelzMetric() *channelz.ChannelInternalMetric { ac.mu.Lock() addr := ac.curAddr.Addr ac.mu.Unlock() - state := ac.getState() - ac.czmu.RLock() - defer ac.czmu.RUnlock() return &channelz.ChannelInternalMetric{ - State: state, + State: ac.getState(), Target: addr, - CallsStarted: ac.callsStarted, - CallsSucceeded: ac.callsSucceeded, - CallsFailed: ac.callsFailed, - LastCallStartedTimestamp: ac.lastCallStartedTime, + CallsStarted: atomic.LoadInt64(&ac.czData.callsStarted), + CallsSucceeded: atomic.LoadInt64(&ac.czData.callsSucceeded), + CallsFailed: atomic.LoadInt64(&ac.czData.callsFailed), + LastCallStartedTimestamp: time.Unix(0, atomic.LoadInt64(&ac.czData.lastCallStartedTime)), } } func (ac *addrConn) incrCallsStarted() { - ac.czmu.Lock() - ac.callsStarted++ - ac.lastCallStartedTime = time.Now() - ac.czmu.Unlock() + atomic.AddInt64(&ac.czData.callsStarted, 1) + atomic.StoreInt64(&ac.czData.lastCallStartedTime, time.Now().UnixNano()) } func (ac *addrConn) incrCallsSucceeded() { - ac.czmu.Lock() - ac.callsSucceeded++ - ac.czmu.Unlock() + atomic.AddInt64(&ac.czData.callsSucceeded, 1) } func (ac *addrConn) incrCallsFailed() { - ac.czmu.Lock() - ac.callsFailed++ - ac.czmu.Unlock() + atomic.AddInt64(&ac.czData.callsFailed, 1) +} + +type retryThrottler struct { + max float64 + thresh float64 + ratio float64 + + mu sync.Mutex + tokens float64 // TODO(dfawley): replace with atomic and remove lock. +} + +// throttle subtracts a retry token from the pool and returns whether a retry +// should be throttled (disallowed) based upon the retry throttling policy in +// the service config. +func (rt *retryThrottler) throttle() bool { + if rt == nil { + return false + } + rt.mu.Lock() + defer rt.mu.Unlock() + rt.tokens-- + if rt.tokens < 0 { + rt.tokens = 0 + } + return rt.tokens <= rt.thresh +} + +func (rt *retryThrottler) successfulRPC() { + if rt == nil { + return + } + rt.mu.Lock() + defer rt.mu.Unlock() + rt.tokens += rt.ratio + if rt.tokens > rt.max { + rt.tokens = rt.max + } +} + +type channelzChannel struct { + cc *ClientConn +} + +func (c *channelzChannel) ChannelzMetric() *channelz.ChannelInternalMetric { + return c.cc.channelzMetric() } // ErrClientConnTimeout indicates that the ClientConn cannot establish the diff --git a/vendor/google.golang.org/grpc/clientconn_state_transition_test.go b/vendor/google.golang.org/grpc/clientconn_state_transition_test.go new file mode 100644 index 0000000000000000000000000000000000000000..bf5bbd8896d8477370015bb67e66be7b26b6023a --- /dev/null +++ b/vendor/google.golang.org/grpc/clientconn_state_transition_test.go @@ -0,0 +1,515 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package grpc + +import ( + "context" + "net" + "sync" + "sync/atomic" + "testing" + "time" + + "golang.org/x/net/http2" + "google.golang.org/grpc/balancer" + "google.golang.org/grpc/connectivity" + "google.golang.org/grpc/internal/leakcheck" + "google.golang.org/grpc/internal/testutils" + "google.golang.org/grpc/resolver" + "google.golang.org/grpc/resolver/manual" +) + +const stateRecordingBalancerName = "state_recoding_balancer" + +var testBalancer = &stateRecordingBalancer{} + +func init() { + balancer.Register(testBalancer) +} + +// These tests use a pipeListener. This listener is similar to net.Listener except that it is unbuffered, so each read +// and write will wait for the other side's corresponding write or read. +func TestStateTransitions_SingleAddress(t *testing.T) { + defer leakcheck.Check(t) + + mctBkp := getMinConnectTimeout() + defer func() { + atomic.StoreInt64((*int64)(&mutableMinConnectTimeout), int64(mctBkp)) + }() + atomic.StoreInt64((*int64)(&mutableMinConnectTimeout), int64(time.Millisecond)*100) + + for _, test := range []struct { + desc string + want []connectivity.State + server func(net.Listener) net.Conn + }{ + { + desc: "When the server returns server preface, the client enters READY.", + want: []connectivity.State{ + connectivity.Connecting, + connectivity.Ready, + }, + server: func(lis net.Listener) net.Conn { + conn, err := lis.Accept() + if err != nil { + t.Error(err) + return nil + } + + go keepReading(conn) + + framer := http2.NewFramer(conn, conn) + if err := framer.WriteSettings(http2.Setting{}); err != nil { + t.Errorf("Error while writing settings frame. %v", err) + return nil + } + + return conn + }, + }, + { + desc: "When the connection is closed, the client enters TRANSIENT FAILURE.", + want: []connectivity.State{ + connectivity.Connecting, + connectivity.TransientFailure, + }, + server: func(lis net.Listener) net.Conn { + conn, err := lis.Accept() + if err != nil { + t.Error(err) + return nil + } + + conn.Close() + return nil + }, + }, + { + desc: `When the server sends its connection preface, but the connection dies before the client can write its +connection preface, the client enters TRANSIENT FAILURE.`, + want: []connectivity.State{ + connectivity.Connecting, + connectivity.TransientFailure, + }, + server: func(lis net.Listener) net.Conn { + conn, err := lis.Accept() + if err != nil { + t.Error(err) + return nil + } + + framer := http2.NewFramer(conn, conn) + if err := framer.WriteSettings(http2.Setting{}); err != nil { + t.Errorf("Error while writing settings frame. %v", err) + return nil + } + + conn.Close() + return nil + }, + }, + { + desc: `When the server reads the client connection preface but does not send its connection preface, the +client enters TRANSIENT FAILURE.`, + want: []connectivity.State{ + connectivity.Connecting, + connectivity.TransientFailure, + }, + server: func(lis net.Listener) net.Conn { + conn, err := lis.Accept() + if err != nil { + t.Error(err) + return nil + } + + go keepReading(conn) + + return conn + }, + }, + } { + t.Log(test.desc) + testStateTransitionSingleAddress(t, test.want, test.server) + } +} + +func testStateTransitionSingleAddress(t *testing.T, want []connectivity.State, server func(net.Listener) net.Conn) { + defer leakcheck.Check(t) + + stateNotifications := make(chan connectivity.State, len(want)) + testBalancer.ResetNotifier(stateNotifications) + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + + pl := testutils.NewPipeListener() + defer pl.Close() + + // Launch the server. + var conn net.Conn + var connMu sync.Mutex + go func() { + connMu.Lock() + conn = server(pl) + connMu.Unlock() + }() + + client, err := DialContext(ctx, "", WithWaitForHandshake(), WithInsecure(), + WithBalancerName(stateRecordingBalancerName), WithDialer(pl.Dialer()), withBackoff(noBackoff{})) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + timeout := time.After(5 * time.Second) + + for i := 0; i < len(want); i++ { + select { + case <-timeout: + t.Fatalf("timed out waiting for state %d (%v) in flow %v", i, want[i], want) + case seen := <-stateNotifications: + if seen != want[i] { + t.Fatalf("expected to see %v at position %d in flow %v, got %v", want[i], i, want, seen) + } + } + } + + connMu.Lock() + defer connMu.Unlock() + if conn != nil { + err = conn.Close() + if err != nil { + t.Fatal(err) + } + } +} + +// When a READY connection is closed, the client enters TRANSIENT FAILURE before CONNECTING. +func TestStateTransition_ReadyToTransientFailure(t *testing.T) { + defer leakcheck.Check(t) + + want := []connectivity.State{ + connectivity.Connecting, + connectivity.Ready, + connectivity.TransientFailure, + connectivity.Connecting, + } + + stateNotifications := make(chan connectivity.State, len(want)) + testBalancer.ResetNotifier(stateNotifications) + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("Error while listening. Err: %v", err) + } + defer lis.Close() + + sawReady := make(chan struct{}) + + // Launch the server. + go func() { + conn, err := lis.Accept() + if err != nil { + t.Error(err) + return + } + + go keepReading(conn) + + framer := http2.NewFramer(conn, conn) + if err := framer.WriteSettings(http2.Setting{}); err != nil { + t.Errorf("Error while writing settings frame. %v", err) + return + } + + // Prevents race between onPrefaceReceipt and onClose. + <-sawReady + + conn.Close() + }() + + client, err := DialContext(ctx, lis.Addr().String(), WithWaitForHandshake(), WithInsecure(), WithBalancerName(stateRecordingBalancerName)) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + timeout := time.After(5 * time.Second) + + for i := 0; i < len(want); i++ { + select { + case <-timeout: + t.Fatalf("timed out waiting for state %d (%v) in flow %v", i, want[i], want) + case seen := <-stateNotifications: + if seen == connectivity.Ready { + close(sawReady) + } + if seen != want[i] { + t.Fatalf("expected to see %v at position %d in flow %v, got %v", want[i], i, want, seen) + } + } + } +} + +// When the first connection is closed, the client enters stays in CONNECTING until it tries the second +// address (which succeeds, and then it enters READY). +func TestStateTransitions_TriesAllAddrsBeforeTransientFailure(t *testing.T) { + defer leakcheck.Check(t) + + want := []connectivity.State{ + connectivity.Connecting, + connectivity.Ready, + } + + stateNotifications := make(chan connectivity.State, len(want)) + testBalancer.ResetNotifier(stateNotifications) + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + + lis1, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("Error while listening. Err: %v", err) + } + defer lis1.Close() + + lis2, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("Error while listening. Err: %v", err) + } + defer lis2.Close() + + server1Done := make(chan struct{}) + server2Done := make(chan struct{}) + + // Launch server 1. + go func() { + conn, err := lis1.Accept() + if err != nil { + t.Error(err) + return + } + + conn.Close() + close(server1Done) + }() + // Launch server 2. + go func() { + conn, err := lis2.Accept() + if err != nil { + t.Error(err) + return + } + + go keepReading(conn) + + framer := http2.NewFramer(conn, conn) + if err := framer.WriteSettings(http2.Setting{}); err != nil { + t.Errorf("Error while writing settings frame. %v", err) + return + } + + close(server2Done) + }() + + rb := manual.NewBuilderWithScheme("whatever") + rb.InitialAddrs([]resolver.Address{ + {Addr: lis1.Addr().String()}, + {Addr: lis2.Addr().String()}, + }) + client, err := DialContext(ctx, "this-gets-overwritten", WithInsecure(), WithWaitForHandshake(), WithBalancerName(stateRecordingBalancerName), withResolverBuilder(rb)) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + timeout := time.After(5 * time.Second) + + for i := 0; i < len(want); i++ { + select { + case <-timeout: + t.Fatalf("timed out waiting for state %d (%v) in flow %v", i, want[i], want) + case seen := <-stateNotifications: + if seen != want[i] { + t.Fatalf("expected to see %v at position %d in flow %v, got %v", want[i], i, want, seen) + } + } + } + select { + case <-timeout: + t.Fatal("saw the correct state transitions, but timed out waiting for client to finish interactions with server 1") + case <-server1Done: + } + select { + case <-timeout: + t.Fatal("saw the correct state transitions, but timed out waiting for client to finish interactions with server 2") + case <-server2Done: + } +} + +// When there are multiple addresses, and we enter READY on one of them, a later closure should cause +// the client to enter TRANSIENT FAILURE before it re-enters CONNECTING. +func TestStateTransitions_MultipleAddrsEntersReady(t *testing.T) { + defer leakcheck.Check(t) + + want := []connectivity.State{ + connectivity.Connecting, + connectivity.Ready, + connectivity.TransientFailure, + connectivity.Connecting, + } + + stateNotifications := make(chan connectivity.State, len(want)) + testBalancer.ResetNotifier(stateNotifications) + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + + lis1, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("Error while listening. Err: %v", err) + } + defer lis1.Close() + + // Never actually gets used; we just want it to be alive so that the resolver has two addresses to target. + lis2, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("Error while listening. Err: %v", err) + } + defer lis2.Close() + + server1Done := make(chan struct{}) + sawReady := make(chan struct{}) + + // Launch server 1. + go func() { + conn, err := lis1.Accept() + if err != nil { + t.Error(err) + return + } + + go keepReading(conn) + + framer := http2.NewFramer(conn, conn) + if err := framer.WriteSettings(http2.Setting{}); err != nil { + t.Errorf("Error while writing settings frame. %v", err) + return + } + + <-sawReady + + conn.Close() + + _, err = lis1.Accept() + if err != nil { + t.Error(err) + return + } + + close(server1Done) + }() + + rb := manual.NewBuilderWithScheme("whatever") + rb.InitialAddrs([]resolver.Address{ + {Addr: lis1.Addr().String()}, + {Addr: lis2.Addr().String()}, + }) + client, err := DialContext(ctx, "this-gets-overwritten", WithInsecure(), WithWaitForHandshake(), WithBalancerName(stateRecordingBalancerName), withResolverBuilder(rb)) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + timeout := time.After(2 * time.Second) + + for i := 0; i < len(want); i++ { + select { + case <-timeout: + t.Fatalf("timed out waiting for state %d (%v) in flow %v", i, want[i], want) + case seen := <-stateNotifications: + if seen == connectivity.Ready { + close(sawReady) + } + if seen != want[i] { + t.Fatalf("expected to see %v at position %d in flow %v, got %v", want[i], i, want, seen) + } + } + } + select { + case <-timeout: + t.Fatal("saw the correct state transitions, but timed out waiting for client to finish interactions with server 1") + case <-server1Done: + } +} + +type stateRecordingBalancer struct { + mu sync.Mutex + notifier chan<- connectivity.State + + balancer.Balancer +} + +func (b *stateRecordingBalancer) HandleSubConnStateChange(sc balancer.SubConn, s connectivity.State) { + b.mu.Lock() + b.notifier <- s + b.mu.Unlock() + + b.Balancer.HandleSubConnStateChange(sc, s) +} + +func (b *stateRecordingBalancer) ResetNotifier(r chan<- connectivity.State) { + b.mu.Lock() + defer b.mu.Unlock() + b.notifier = r +} + +func (b *stateRecordingBalancer) Close() { + b.mu.Lock() + u := b.Balancer + b.mu.Unlock() + u.Close() +} + +func (b *stateRecordingBalancer) Name() string { + return stateRecordingBalancerName +} + +func (b *stateRecordingBalancer) Build(cc balancer.ClientConn, opts balancer.BuildOptions) balancer.Balancer { + b.mu.Lock() + b.Balancer = balancer.Get(PickFirstBalancerName).Build(cc, opts) + b.mu.Unlock() + return b +} + +type noBackoff struct{} + +func (b noBackoff) Backoff(int) time.Duration { return time.Duration(0) } + +// Keep reading until something causes the connection to die (EOF, server closed, etc). Useful +// as a tool for mindlessly keeping the connection healthy, since the client will error if +// things like client prefaces are not accepted in a timely fashion. +func keepReading(conn net.Conn) { + buf := make([]byte, 1024) + for _, err := conn.Read(buf); err == nil; _, err = conn.Read(buf) { + } +} diff --git a/vendor/google.golang.org/grpc/clientconn_test.go b/vendor/google.golang.org/grpc/clientconn_test.go index fd239d36da4d8ef516c91ee5143d3f4419e3056d..467e2ef5ac9eb172a667ac3b77c1c0b31d9f42e3 100644 --- a/vendor/google.golang.org/grpc/clientconn_test.go +++ b/vendor/google.golang.org/grpc/clientconn_test.go @@ -19,18 +19,22 @@ package grpc import ( + "context" + "errors" + "fmt" "math" "net" "sync/atomic" "testing" "time" - "golang.org/x/net/context" "golang.org/x/net/http2" "google.golang.org/grpc/connectivity" "google.golang.org/grpc/credentials" "google.golang.org/grpc/internal/backoff" + "google.golang.org/grpc/internal/envconfig" "google.golang.org/grpc/internal/leakcheck" + "google.golang.org/grpc/internal/transport" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/naming" "google.golang.org/grpc/resolver" @@ -129,13 +133,90 @@ func TestDialWithMultipleBackendsNotSendingServerPreface(t *testing.T) { } } +var allReqHSSettings = []envconfig.RequireHandshakeSetting{ + envconfig.RequireHandshakeOff, + envconfig.RequireHandshakeOn, + envconfig.RequireHandshakeHybrid, +} +var reqNoHSSettings = []envconfig.RequireHandshakeSetting{ + envconfig.RequireHandshakeOff, + envconfig.RequireHandshakeHybrid, +} +var reqHSBeforeSuccess = []envconfig.RequireHandshakeSetting{ + envconfig.RequireHandshakeOn, + envconfig.RequireHandshakeHybrid, +} + func TestDialWaitsForServerSettings(t *testing.T) { + // Restore current setting after test. + old := envconfig.RequireHandshake + defer func() { envconfig.RequireHandshake = old }() + + defer leakcheck.Check(t) + + // Test with all environment variable settings, which should not impact the + // test case since WithWaitForHandshake has higher priority. + for _, setting := range allReqHSSettings { + envconfig.RequireHandshake = setting + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("Error while listening. Err: %v", err) + } + defer lis.Close() + done := make(chan struct{}) + sent := make(chan struct{}) + dialDone := make(chan struct{}) + go func() { // Launch the server. + defer func() { + close(done) + }() + conn, err := lis.Accept() + if err != nil { + t.Errorf("Error while accepting. Err: %v", err) + return + } + defer conn.Close() + // Sleep for a little bit to make sure that Dial on client + // side blocks until settings are received. + time.Sleep(100 * time.Millisecond) + framer := http2.NewFramer(conn, conn) + close(sent) + if err := framer.WriteSettings(http2.Setting{}); err != nil { + t.Errorf("Error while writing settings. Err: %v", err) + return + } + <-dialDone // Close conn only after dial returns. + }() + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + client, err := DialContext(ctx, lis.Addr().String(), WithInsecure(), WithWaitForHandshake(), WithBlock()) + close(dialDone) + if err != nil { + t.Fatalf("Error while dialing. Err: %v", err) + } + defer client.Close() + select { + case <-sent: + default: + t.Fatalf("Dial returned before server settings were sent") + } + <-done + } +} + +func TestDialWaitsForServerSettingsViaEnv(t *testing.T) { + // Set default behavior and restore current setting after test. + old := envconfig.RequireHandshake + envconfig.RequireHandshake = envconfig.RequireHandshakeOn + defer func() { envconfig.RequireHandshake = old }() + defer leakcheck.Check(t) - server, err := net.Listen("tcp", "localhost:0") + + lis, err := net.Listen("tcp", "localhost:0") if err != nil { t.Fatalf("Error while listening. Err: %v", err) } - defer server.Close() + defer lis.Close() done := make(chan struct{}) sent := make(chan struct{}) dialDone := make(chan struct{}) @@ -143,7 +224,7 @@ func TestDialWaitsForServerSettings(t *testing.T) { defer func() { close(done) }() - conn, err := server.Accept() + conn, err := lis.Accept() if err != nil { t.Errorf("Error while accepting. Err: %v", err) return @@ -151,7 +232,7 @@ func TestDialWaitsForServerSettings(t *testing.T) { defer conn.Close() // Sleep for a little bit to make sure that Dial on client // side blocks until settings are received. - time.Sleep(500 * time.Millisecond) + time.Sleep(100 * time.Millisecond) framer := http2.NewFramer(conn, conn) close(sent) if err := framer.WriteSettings(http2.Setting{}); err != nil { @@ -162,10 +243,9 @@ func TestDialWaitsForServerSettings(t *testing.T) { }() ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - client, err := DialContext(ctx, server.Addr().String(), WithInsecure(), WithWaitForHandshake(), WithBlock()) + client, err := DialContext(ctx, lis.Addr().String(), WithInsecure(), WithBlock()) close(dialDone) if err != nil { - cancel() t.Fatalf("Error while dialing. Err: %v", err) } defer client.Close() @@ -175,93 +255,251 @@ func TestDialWaitsForServerSettings(t *testing.T) { t.Fatalf("Dial returned before server settings were sent") } <-done +} + +func TestDialWaitsForServerSettingsAndFails(t *testing.T) { + // Restore current setting after test. + old := envconfig.RequireHandshake + defer func() { envconfig.RequireHandshake = old }() + defer leakcheck.Check(t) + + for _, setting := range allReqHSSettings { + envconfig.RequireHandshake = setting + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("Error while listening. Err: %v", err) + } + done := make(chan struct{}) + numConns := 0 + go func() { // Launch the server. + defer func() { + close(done) + }() + for { + conn, err := lis.Accept() + if err != nil { + break + } + numConns++ + defer conn.Close() + } + }() + getMinConnectTimeout = func() time.Duration { return time.Second / 4 } + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + client, err := DialContext(ctx, lis.Addr().String(), WithInsecure(), WithWaitForHandshake(), WithBlock(), withBackoff(noBackoff{})) + lis.Close() + if err == nil { + client.Close() + t.Fatalf("Unexpected success (err=nil) while dialing") + } + if err != context.DeadlineExceeded { + t.Fatalf("DialContext(_) = %v; want context.DeadlineExceeded", err) + } + if numConns < 2 { + t.Fatalf("dial attempts: %v; want > 1", numConns) + } + <-done + } } -func TestCloseConnectionWhenServerPrefaceNotReceived(t *testing.T) { - mctBkp := getMinConnectTimeout() - // Call this only after transportMonitor goroutine has ended. - defer func() { - atomic.StoreInt64((*int64)(&mutableMinConnectTimeout), int64(mctBkp)) +func TestDialWaitsForServerSettingsViaEnvAndFails(t *testing.T) { + // Set default behavior and restore current setting after test. + old := envconfig.RequireHandshake + envconfig.RequireHandshake = envconfig.RequireHandshakeOn + defer func() { envconfig.RequireHandshake = old }() - }() defer leakcheck.Check(t) - atomic.StoreInt64((*int64)(&mutableMinConnectTimeout), int64(time.Millisecond)*500) + lis, err := net.Listen("tcp", "localhost:0") if err != nil { t.Fatalf("Error while listening. Err: %v", err) } - var ( - conn2 net.Conn - over uint32 - ) - defer func() { - lis.Close() - // conn2 shouldn't be closed until the client has - // observed a successful test. - if conn2 != nil { - conn2.Close() - } - }() done := make(chan struct{}) + numConns := 0 go func() { // Launch the server. - defer close(done) - conn1, err := lis.Accept() + defer func() { + close(done) + }() + for { + conn, err := lis.Accept() + if err != nil { + break + } + numConns++ + defer conn.Close() + } + }() + getMinConnectTimeout = func() time.Duration { return time.Second / 4 } + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + client, err := DialContext(ctx, lis.Addr().String(), WithInsecure(), WithBlock(), withBackoff(noBackoff{})) + lis.Close() + if err == nil { + client.Close() + t.Fatalf("Unexpected success (err=nil) while dialing") + } + if err != context.DeadlineExceeded { + t.Fatalf("DialContext(_) = %v; want context.DeadlineExceeded", err) + } + if numConns < 2 { + t.Fatalf("dial attempts: %v; want > 1", numConns) + } + <-done +} + +func TestDialDoesNotWaitForServerSettings(t *testing.T) { + // Restore current setting after test. + old := envconfig.RequireHandshake + defer func() { envconfig.RequireHandshake = old }() + + defer leakcheck.Check(t) + + // Test with "off" and "hybrid". + for _, setting := range reqNoHSSettings { + envconfig.RequireHandshake = setting + lis, err := net.Listen("tcp", "localhost:0") if err != nil { - t.Errorf("Error while accepting. Err: %v", err) - return + t.Fatalf("Error while listening. Err: %v", err) } - defer conn1.Close() - // Don't send server settings and the client should close the connection and try again. - conn2, err = lis.Accept() // Accept a reconnection request from client. + defer lis.Close() + done := make(chan struct{}) + dialDone := make(chan struct{}) + go func() { // Launch the server. + defer func() { + close(done) + }() + conn, err := lis.Accept() + if err != nil { + t.Errorf("Error while accepting. Err: %v", err) + return + } + defer conn.Close() + <-dialDone // Close conn only after dial returns. + }() + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + client, err := DialContext(ctx, lis.Addr().String(), WithInsecure(), WithBlock()) + if err != nil { - t.Errorf("Error while accepting. Err: %v", err) - return + t.Fatalf("DialContext returned err =%v; want nil", err) } - framer := http2.NewFramer(conn2, conn2) - if err = framer.WriteSettings(http2.Setting{}); err != nil { - t.Errorf("Error while writing settings. Err: %v", err) - return + defer client.Close() + + if state := client.GetState(); state != connectivity.Ready { + t.Fatalf("client.GetState() = %v; want connectivity.Ready", state) } - b := make([]byte, 8) - for { - _, err = conn2.Read(b) - if err == nil { - continue + close(dialDone) + <-done + } +} + +func TestCloseConnectionWhenServerPrefaceNotReceived(t *testing.T) { + // Restore current setting after test. + old := envconfig.RequireHandshake + defer func() { envconfig.RequireHandshake = old }() + + // 1. Client connects to a server that doesn't send preface. + // 2. After minConnectTimeout(500 ms here), client disconnects and retries. + // 3. The new server sends its preface. + // 4. Client doesn't kill the connection this time. + mctBkp := getMinConnectTimeout() + defer func() { + atomic.StoreInt64((*int64)(&mutableMinConnectTimeout), int64(mctBkp)) + }() + defer leakcheck.Check(t) + atomic.StoreInt64((*int64)(&mutableMinConnectTimeout), int64(time.Millisecond)*500) + + // Test with "on" and "hybrid". + for _, setting := range reqHSBeforeSuccess { + envconfig.RequireHandshake = setting + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("Error while listening. Err: %v", err) + } + var ( + conn2 net.Conn + over uint32 + ) + defer func() { + lis.Close() + // conn2 shouldn't be closed until the client has + // observed a successful test. + if conn2 != nil { + conn2.Close() } - if atomic.LoadUint32(&over) == 1 { - // The connection stayed alive for the timer. - // Success. + }() + done := make(chan struct{}) + accepted := make(chan struct{}) + go func() { // Launch the server. + defer close(done) + conn1, err := lis.Accept() + if err != nil { + t.Errorf("Error while accepting. Err: %v", err) return } - t.Errorf("Unexpected error while reading. Err: %v, want timeout error", err) - break + defer conn1.Close() + // Don't send server settings and the client should close the connection and try again. + conn2, err = lis.Accept() // Accept a reconnection request from client. + if err != nil { + t.Errorf("Error while accepting. Err: %v", err) + return + } + close(accepted) + framer := http2.NewFramer(conn2, conn2) + if err = framer.WriteSettings(http2.Setting{}); err != nil { + t.Errorf("Error while writing settings. Err: %v", err) + return + } + b := make([]byte, 8) + for { + _, err = conn2.Read(b) + if err == nil { + continue + } + if atomic.LoadUint32(&over) == 1 { + // The connection stayed alive for the timer. + // Success. + return + } + t.Errorf("Unexpected error while reading. Err: %v, want timeout error", err) + break + } + }() + client, err := Dial(lis.Addr().String(), WithInsecure()) + if err != nil { + t.Fatalf("Error while dialing. Err: %v", err) } - }() - client, err := Dial(lis.Addr().String(), WithInsecure()) - if err != nil { - t.Fatalf("Error while dialing. Err: %v", err) + // wait for connection to be accepted on the server. + timer := time.NewTimer(time.Second * 10) + select { + case <-accepted: + case <-timer.C: + t.Fatalf("Client didn't make another connection request in time.") + } + // Make sure the connection stays alive for sometime. + time.Sleep(time.Second) + atomic.StoreUint32(&over, 1) + client.Close() + <-done } - time.Sleep(time.Second * 2) // Let things play out. - atomic.StoreUint32(&over, 1) - lis.Close() - client.Close() - <-done } func TestBackoffWhenNoServerPrefaceReceived(t *testing.T) { defer leakcheck.Check(t) - server, err := net.Listen("tcp", "localhost:0") + lis, err := net.Listen("tcp", "localhost:0") if err != nil { t.Fatalf("Error while listening. Err: %v", err) } - defer server.Close() + defer lis.Close() done := make(chan struct{}) go func() { // Launch the server. defer func() { close(done) }() - conn, err := server.Accept() // Accept the connection only to close it immediately. + conn, err := lis.Accept() // Accept the connection only to close it immediately. if err != nil { t.Errorf("Error while accepting. Err: %v", err) return @@ -271,7 +509,7 @@ func TestBackoffWhenNoServerPrefaceReceived(t *testing.T) { var prevDuration time.Duration // Make sure the retry attempts are backed off properly. for i := 0; i < 3; i++ { - conn, err := server.Accept() + conn, err := lis.Accept() if err != nil { t.Errorf("Error while accepting. Err: %v", err) return @@ -287,7 +525,7 @@ func TestBackoffWhenNoServerPrefaceReceived(t *testing.T) { prevAt = meow } }() - client, err := Dial(server.Addr().String(), WithInsecure()) + client, err := Dial(lis.Addr().String(), WithInsecure()) if err != nil { t.Fatalf("Error while dialing. Err: %v", err) } @@ -430,6 +668,26 @@ func TestDialContextCancel(t *testing.T) { } } +type failFastError struct{} + +func (failFastError) Error() string { return "failfast" } +func (failFastError) Temporary() bool { return false } + +func TestDialContextFailFast(t *testing.T) { + defer leakcheck.Check(t) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + failErr := failFastError{} + dialer := func(string, time.Duration) (net.Conn, error) { + return nil, failErr + } + + _, err := DialContext(ctx, "Non-Existent.Server:80", WithBlock(), WithInsecure(), WithDialer(dialer), FailOnNonTempDialError(true)) + if terr, ok := err.(transport.ConnectionError); !ok || terr.Origin() != failErr { + t.Fatalf("DialContext() = _, %v, want _, %v", err, failErr) + } +} + // blockingBalancer mimics the behavior of balancers whose initialization takes a long time. // In this test, reading from blockingBalancer.Notify() blocks forever. type blockingBalancer struct { @@ -602,6 +860,22 @@ func TestResolverServiceConfigBeforeAddressNotPanic(t *testing.T) { time.Sleep(time.Second) // Sleep to make sure the service config is handled by ClientConn. } +func TestResolverServiceConfigWhileClosingNotPanic(t *testing.T) { + defer leakcheck.Check(t) + for i := 0; i < 10; i++ { // Run this multiple times to make sure it doesn't panic. + r, rcleanup := manual.GenerateAndRegisterManualResolver() + defer rcleanup() + + cc, err := Dial(r.Scheme()+":///test.server", WithInsecure()) + if err != nil { + t.Fatalf("failed to dial: %v", err) + } + // Send a new service config while closing the ClientConn. + go cc.Close() + go r.NewServiceConfig(`{"loadBalancingPolicy": "round_robin"}`) // This should not panic. + } +} + func TestResolverEmptyUpdateNotPanic(t *testing.T) { defer leakcheck.Check(t) r, rcleanup := manual.GenerateAndRegisterManualResolver() @@ -639,7 +913,7 @@ func TestClientUpdatesParamsAfterGoAway(t *testing.T) { t.Fatalf("Dial(%s, _) = _, %v, want _, ", addr, err) } defer cc.Close() - time.Sleep(1 * time.Second) + time.Sleep(time.Second) cc.mu.RLock() defer cc.mu.RUnlock() v := cc.mkp.Time @@ -670,9 +944,79 @@ func TestDisableServiceConfigOption(t *testing.T) { } ] }`) - time.Sleep(1 * time.Second) + time.Sleep(time.Second) m := cc.GetMethodConfig("/foo/Bar") if m.WaitForReady != nil { t.Fatalf("want: method (\"/foo/bar/\") config to be empty, got: %v", m) } } + +func TestGetClientConnTarget(t *testing.T) { + addr := "nonexist:///non.existent" + cc, err := Dial(addr, WithInsecure()) + if err != nil { + t.Fatalf("Dial(%s, _) = _, %v, want _, ", addr, err) + } + defer cc.Close() + if cc.Target() != addr { + t.Fatalf("Target() = %s, want %s", cc.Target(), addr) + } +} + +type backoffForever struct{} + +func (b backoffForever) Backoff(int) time.Duration { return time.Duration(math.MaxInt64) } + +func TestResetConnectBackoff(t *testing.T) { + defer leakcheck.Check(t) + dials := make(chan struct{}) + defer func() { // If we fail, let the http2client break out of dialing. + select { + case <-dials: + default: + } + }() + dialer := func(string, time.Duration) (net.Conn, error) { + dials <- struct{}{} + return nil, errors.New("failed to fake dial") + } + cc, err := Dial("any", WithInsecure(), WithDialer(dialer), withBackoff(backoffForever{})) + if err != nil { + t.Fatalf("Dial() = _, %v; want _, nil", err) + } + defer cc.Close() + select { + case <-dials: + case <-time.NewTimer(10 * time.Second).C: + t.Fatal("Failed to call dial within 10s") + } + + select { + case <-dials: + t.Fatal("Dial called unexpectedly before resetting backoff") + case <-time.NewTimer(100 * time.Millisecond).C: + } + + cc.ResetConnectBackoff() + + select { + case <-dials: + case <-time.NewTimer(10 * time.Second).C: + t.Fatal("Failed to call dial within 10s after resetting backoff") + } +} + +func TestBackoffCancel(t *testing.T) { + defer leakcheck.Check(t) + dialStrCh := make(chan string) + cc, err := Dial("any", WithInsecure(), WithDialer(func(t string, _ time.Duration) (net.Conn, error) { + dialStrCh <- t + return nil, fmt.Errorf("test dialer, always error") + })) + if err != nil { + t.Fatalf("Failed to create ClientConn: %v", err) + } + <-dialStrCh + cc.Close() + // Should not leak. May need -count 5000 to exercise. +} diff --git a/vendor/google.golang.org/grpc/connectivity/connectivity.go b/vendor/google.golang.org/grpc/connectivity/connectivity.go index 568ef5dc68baa87c9d9d23c2e96c5a010d0ca943..b1d7dbc5470dbd04a50178f93afccd56b7bfad9a 100644 --- a/vendor/google.golang.org/grpc/connectivity/connectivity.go +++ b/vendor/google.golang.org/grpc/connectivity/connectivity.go @@ -22,7 +22,8 @@ package connectivity import ( - "golang.org/x/net/context" + "context" + "google.golang.org/grpc/grpclog" ) diff --git a/vendor/google.golang.org/grpc/credentials/alts/alts.go b/vendor/google.golang.org/grpc/credentials/alts/alts.go index 940056543d3c0f2231d0beb28a82c9d53d230a4c..4cb93f164737bf39a0f3510c1b1de59f6634e9ea 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/alts.go +++ b/vendor/google.golang.org/grpc/credentials/alts/alts.go @@ -24,18 +24,18 @@ package alts import ( + "context" "errors" "fmt" "net" "sync" "time" - "golang.org/x/net/context" "google.golang.org/grpc/credentials" - "google.golang.org/grpc/credentials/alts/core" - "google.golang.org/grpc/credentials/alts/core/handshaker" - "google.golang.org/grpc/credentials/alts/core/handshaker/service" - altspb "google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp" + core "google.golang.org/grpc/credentials/alts/internal" + "google.golang.org/grpc/credentials/alts/internal/handshaker" + "google.golang.org/grpc/credentials/alts/internal/handshaker/service" + altspb "google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp" "google.golang.org/grpc/grpclog" ) @@ -66,7 +66,7 @@ var ( // ErrUntrustedPlatform is returned from ClientHandshake and // ServerHandshake is running on a platform where the trustworthiness of // the handshaker service is not guaranteed. - ErrUntrustedPlatform = errors.New("untrusted platform") + ErrUntrustedPlatform = errors.New("ALTS: untrusted platform. ALTS is only supported on GCP") ) // AuthInfo exposes security information from the ALTS handshake to the @@ -190,6 +190,7 @@ func (g *altsTC) ClientHandshake(ctx context.Context, addr string, rawConn net.C }() opts := handshaker.DefaultClientHandshakerOptions() + opts.TargetName = addr opts.TargetServiceAccounts = g.accounts opts.RPCVersions = &altspb.RpcProtocolVersions{ MaxRpcVersion: maxRPCVersion, diff --git a/vendor/google.golang.org/grpc/credentials/alts/alts_test.go b/vendor/google.golang.org/grpc/credentials/alts/alts_test.go index 6b041d9995deea956784ce14b9ca348434512d04..43c7732c0349409696681eb69181b712ae6451f4 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/alts_test.go +++ b/vendor/google.golang.org/grpc/credentials/alts/alts_test.go @@ -23,7 +23,7 @@ import ( "testing" "github.com/golang/protobuf/proto" - altspb "google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp" + altspb "google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp" ) func TestInfoServerName(t *testing.T) { diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/authinfo/authinfo.go b/vendor/google.golang.org/grpc/credentials/alts/internal/authinfo/authinfo.go similarity index 97% rename from vendor/google.golang.org/grpc/credentials/alts/core/authinfo/authinfo.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/authinfo/authinfo.go index 2fe54b74ecc688998248eddcb2893e10fdd39b2c..ed628dc7cd2ca16366f10a18238fc0c23efa95d0 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/core/authinfo/authinfo.go +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/authinfo/authinfo.go @@ -21,7 +21,7 @@ package authinfo import ( "google.golang.org/grpc/credentials" - altspb "google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp" + altspb "google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp" ) var _ credentials.AuthInfo = (*altsAuthInfo)(nil) diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/authinfo/authinfo_test.go b/vendor/google.golang.org/grpc/credentials/alts/internal/authinfo/authinfo_test.go similarity index 98% rename from vendor/google.golang.org/grpc/credentials/alts/core/authinfo/authinfo_test.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/authinfo/authinfo_test.go index 635d80491e3313e5acd8338a1d508ba3971446e3..91d9ffef4dfe75f746ace31850a0b97ccf77ca69 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/core/authinfo/authinfo_test.go +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/authinfo/authinfo_test.go @@ -22,7 +22,7 @@ import ( "reflect" "testing" - altspb "google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp" + altspb "google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp" ) const ( diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/common.go b/vendor/google.golang.org/grpc/credentials/alts/internal/common.go similarity index 92% rename from vendor/google.golang.org/grpc/credentials/alts/core/common.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/common.go index b7baf77ac83b399151413da5466a70b67b2ae2e6..33fba81239ad18ebc1e0ccb12d5799ca666cc2e2 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/core/common.go +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/common.go @@ -18,14 +18,13 @@ //go:generate ./regenerate.sh -// Package core contains common core functionality for ALTS. -// Disclaimer: users should NEVER reference this package directly. -package core +// Package internal contains common core functionality for ALTS. +package internal import ( + "context" "net" - "golang.org/x/net/context" "google.golang.org/grpc/credentials" ) diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/conn/aeadrekey.go b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/aeadrekey.go similarity index 100% rename from vendor/google.golang.org/grpc/credentials/alts/core/conn/aeadrekey.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/conn/aeadrekey.go diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/conn/aeadrekey_test.go b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/aeadrekey_test.go similarity index 100% rename from vendor/google.golang.org/grpc/credentials/alts/core/conn/aeadrekey_test.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/conn/aeadrekey_test.go diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/conn/aes128gcm.go b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcm.go similarity index 93% rename from vendor/google.golang.org/grpc/credentials/alts/core/conn/aes128gcm.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcm.go index 0c4fe33918a7685bbebdb05c71ae1a7d7bf61388..04e0adb6c90860f5cdf5a5c970f5402ad3ce6d54 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/core/conn/aes128gcm.go +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcm.go @@ -22,7 +22,7 @@ import ( "crypto/aes" "crypto/cipher" - "google.golang.org/grpc/credentials/alts/core" + core "google.golang.org/grpc/credentials/alts/internal" ) const ( @@ -38,8 +38,8 @@ type aes128gcm struct { // inCounter is used in ALTS record to check that incoming counters are // as expected, since ALTS record guarantees that messages are unwrapped // in the same order that the peer wrapped them. - inCounter counter - outCounter counter + inCounter Counter + outCounter Counter aead cipher.AEAD } @@ -54,8 +54,8 @@ func NewAES128GCM(side core.Side, key []byte) (ALTSRecordCrypto, error) { return nil, err } return &aes128gcm{ - inCounter: newInCounter(side, overflowLenAES128GCM), - outCounter: newOutCounter(side, overflowLenAES128GCM), + inCounter: NewInCounter(side, overflowLenAES128GCM), + outCounter: NewOutCounter(side, overflowLenAES128GCM), aead: a, }, nil } diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/conn/aes128gcm_test.go b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcm_test.go similarity index 94% rename from vendor/google.golang.org/grpc/credentials/alts/core/conn/aes128gcm_test.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcm_test.go index c2fca4dd532d57ab6d17b93cfcba1c337cd4597d..90d483b0ad0130f66d2421ee339ae85534f42873 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/core/conn/aes128gcm_test.go +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcm_test.go @@ -22,7 +22,7 @@ import ( "bytes" "testing" - "google.golang.org/grpc/credentials/alts/core" + core "google.golang.org/grpc/credentials/alts/internal" ) // cryptoTestVector is struct for a GCM test vector @@ -43,12 +43,12 @@ func getGCMCryptoPair(key []byte, counter []byte, t *testing.T) (ALTSRecordCrypt } // set counter if provided. if counter != nil { - if counterSide(counter) == core.ClientSide { - client.(*aes128gcm).outCounter = counterFromValue(counter, overflowLenAES128GCM) - server.(*aes128gcm).inCounter = counterFromValue(counter, overflowLenAES128GCM) + if CounterSide(counter) == core.ClientSide { + client.(*aes128gcm).outCounter = CounterFromValue(counter, overflowLenAES128GCM) + server.(*aes128gcm).inCounter = CounterFromValue(counter, overflowLenAES128GCM) } else { - server.(*aes128gcm).outCounter = counterFromValue(counter, overflowLenAES128GCM) - client.(*aes128gcm).inCounter = counterFromValue(counter, overflowLenAES128GCM) + server.(*aes128gcm).outCounter = CounterFromValue(counter, overflowLenAES128GCM) + client.(*aes128gcm).inCounter = CounterFromValue(counter, overflowLenAES128GCM) } } return client, server @@ -150,7 +150,7 @@ func TestAES128GCMEncrypt(t *testing.T) { } { // Test encryption and decryption for aes128gcm. client, server := getGCMCryptoPair(test.key, test.counter, t) - if counterSide(test.counter) == core.ClientSide { + if CounterSide(test.counter) == core.ClientSide { testGCMEncryptionDecryption(client, server, &test, false, t) } else { testGCMEncryptionDecryption(server, client, &test, false, t) diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/conn/aes128gcmrekey.go b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcmrekey.go similarity index 94% rename from vendor/google.golang.org/grpc/credentials/alts/core/conn/aes128gcmrekey.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcmrekey.go index 4b5ecf400bb9d60259c070698110e35482d21ae4..6a9035ea254f82d2b4fdd4b08669d2aece028545 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/core/conn/aes128gcmrekey.go +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcmrekey.go @@ -21,7 +21,7 @@ package conn import ( "crypto/cipher" - "google.golang.org/grpc/credentials/alts/core" + core "google.golang.org/grpc/credentials/alts/internal" ) const ( @@ -43,8 +43,8 @@ type aes128gcmRekey struct { // inCounter is used in ALTS record to check that incoming counters are // as expected, since ALTS record guarantees that messages are unwrapped // in the same order that the peer wrapped them. - inCounter counter - outCounter counter + inCounter Counter + outCounter Counter inAEAD cipher.AEAD outAEAD cipher.AEAD } @@ -54,8 +54,8 @@ type aes128gcmRekey struct { // are used as a key for HKDF-expand and the remainining 12 bytes are used // as a random mask for the counter. func NewAES128GCMRekey(side core.Side, key []byte) (ALTSRecordCrypto, error) { - inCounter := newInCounter(side, overflowLenAES128GCMRekey) - outCounter := newOutCounter(side, overflowLenAES128GCMRekey) + inCounter := NewInCounter(side, overflowLenAES128GCMRekey) + outCounter := NewOutCounter(side, overflowLenAES128GCMRekey) inAEAD, err := newRekeyAEAD(key) if err != nil { return nil, err diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/conn/aes128gcmrekey_test.go b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcmrekey_test.go similarity index 91% rename from vendor/google.golang.org/grpc/credentials/alts/core/conn/aes128gcmrekey_test.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcmrekey_test.go index 9f31a0fa20585b0ab31c9932d1b522291d983598..3aa31f2d3fbdb72a68a39d6db5b1b541fde98019 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/core/conn/aes128gcmrekey_test.go +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcmrekey_test.go @@ -21,7 +21,7 @@ package conn import ( "testing" - "google.golang.org/grpc/credentials/alts/core" + core "google.golang.org/grpc/credentials/alts/internal" ) // cryptoTestVector is struct for a rekey test vector @@ -41,12 +41,12 @@ func getRekeyCryptoPair(key []byte, counter []byte, t *testing.T) (ALTSRecordCry } // set counter if provided. if counter != nil { - if counterSide(counter) == core.ClientSide { - client.(*aes128gcmRekey).outCounter = counterFromValue(counter, overflowLenAES128GCMRekey) - server.(*aes128gcmRekey).inCounter = counterFromValue(counter, overflowLenAES128GCMRekey) + if CounterSide(counter) == core.ClientSide { + client.(*aes128gcmRekey).outCounter = CounterFromValue(counter, overflowLenAES128GCMRekey) + server.(*aes128gcmRekey).inCounter = CounterFromValue(counter, overflowLenAES128GCMRekey) } else { - server.(*aes128gcmRekey).outCounter = counterFromValue(counter, overflowLenAES128GCMRekey) - client.(*aes128gcmRekey).inCounter = counterFromValue(counter, overflowLenAES128GCMRekey) + server.(*aes128gcmRekey).outCounter = CounterFromValue(counter, overflowLenAES128GCMRekey) + client.(*aes128gcmRekey).inCounter = CounterFromValue(counter, overflowLenAES128GCMRekey) } } return client, server diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/conn/common.go b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/common.go similarity index 100% rename from vendor/google.golang.org/grpc/credentials/alts/core/conn/common.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/conn/common.go diff --git a/vendor/google.golang.org/grpc/credentials/alts/internal/conn/counter.go b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/counter.go new file mode 100644 index 0000000000000000000000000000000000000000..9f00aca0b614fe7267078cf1316f07cc6443ddf8 --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/counter.go @@ -0,0 +1,62 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package conn + +import ( + "errors" +) + +const counterLen = 12 + +var ( + errInvalidCounter = errors.New("invalid counter") +) + +// Counter is a 96-bit, little-endian counter. +type Counter struct { + value [counterLen]byte + invalid bool + overflowLen int +} + +// Value returns the current value of the counter as a byte slice. +func (c *Counter) Value() ([]byte, error) { + if c.invalid { + return nil, errInvalidCounter + } + return c.value[:], nil +} + +// Inc increments the counter and checks for overflow. +func (c *Counter) Inc() { + // If the counter is already invalid, there is no need to increase it. + if c.invalid { + return + } + i := 0 + for ; i < c.overflowLen; i++ { + c.value[i]++ + if c.value[i] != 0 { + break + } + } + if i == c.overflowLen { + c.invalid = true + } +} diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/conn/counter_test.go b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/counter_test.go similarity index 88% rename from vendor/google.golang.org/grpc/credentials/alts/core/conn/counter_test.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/conn/counter_test.go index faf563697ce1a7fe54088894d9b36f490cf8877d..c3027b9e94d9437b3dee20657704fe6f022aaa9b 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/core/conn/counter_test.go +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/counter_test.go @@ -22,7 +22,7 @@ import ( "bytes" "testing" - "google.golang.org/grpc/credentials/alts/core" + core "google.golang.org/grpc/credentials/alts/internal" ) const ( @@ -31,17 +31,17 @@ const ( func TestCounterSides(t *testing.T) { for _, side := range []core.Side{core.ClientSide, core.ServerSide} { - outCounter := newOutCounter(side, testOverflowLen) - inCounter := newInCounter(side, testOverflowLen) + outCounter := NewOutCounter(side, testOverflowLen) + inCounter := NewInCounter(side, testOverflowLen) for i := 0; i < 1024; i++ { value, _ := outCounter.Value() - if g, w := counterSide(value), side; g != w { - t.Errorf("after %d iterations, counterSide(outCounter.Value()) = %v, want %v", i, g, w) + if g, w := CounterSide(value), side; g != w { + t.Errorf("after %d iterations, CounterSide(outCounter.Value()) = %v, want %v", i, g, w) break } value, _ = inCounter.Value() - if g, w := counterSide(value), side; g == w { - t.Errorf("after %d iterations, counterSide(inCounter.Value()) = %v, want %v", i, g, w) + if g, w := CounterSide(value), side; g == w { + t.Errorf("after %d iterations, CounterSide(inCounter.Value()) = %v, want %v", i, g, w) break } outCounter.Inc() @@ -80,7 +80,7 @@ func TestCounterInc(t *testing.T) { want: []byte{0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80}, }, } { - c := counterFromValue(test.counter, overflowLenAES128GCM) + c := CounterFromValue(test.counter, overflowLenAES128GCM) c.Inc() value, _ := c.Value() if g, w := value, test.want; !bytes.Equal(g, w) || c.invalid { @@ -116,7 +116,7 @@ func TestRolloverCounter(t *testing.T) { overflowLen: 8, }, } { - c := counterFromValue(test.value, overflowLenAES128GCM) + c := CounterFromValue(test.value, overflowLenAES128GCM) // First Inc() + Value() should work. c.Inc() diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/conn/record.go b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/record.go similarity index 99% rename from vendor/google.golang.org/grpc/credentials/alts/core/conn/record.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/conn/record.go index cb514ebe33b5edcce9fc82c020c3ec4f088ad2d2..fd5a53d9a7aaee6fdd8bc705d1dc201bac122211 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/core/conn/record.go +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/record.go @@ -26,7 +26,7 @@ import ( "math" "net" - "google.golang.org/grpc/credentials/alts/core" + core "google.golang.org/grpc/credentials/alts/internal" ) // ALTSRecordCrypto is the interface for gRPC ALTS record protocol. diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/conn/record_test.go b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/record_test.go similarity index 99% rename from vendor/google.golang.org/grpc/credentials/alts/core/conn/record_test.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/conn/record_test.go index 5c3b8e2c5c497da99b93581bd6c0c1560770dc12..76e05549b66e359d8fd7c371927fda69fa19d9bf 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/core/conn/record_test.go +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/record_test.go @@ -28,7 +28,7 @@ import ( "reflect" "testing" - "google.golang.org/grpc/credentials/alts/core" + core "google.golang.org/grpc/credentials/alts/internal" ) var ( diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/conn/counter.go b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/utils.go similarity index 53% rename from vendor/google.golang.org/grpc/credentials/alts/core/conn/counter.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/conn/utils.go index 754dcfaa5832bfc80e5db3c81427dbc3a5a39e06..84821fa2543942a9e98a12737baf90e7831ae734 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/core/conn/counter.go +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/utils.go @@ -18,28 +18,11 @@ package conn -import ( - "errors" +import core "google.golang.org/grpc/credentials/alts/internal" - "google.golang.org/grpc/credentials/alts/core" -) - -const counterLen = 12 - -var ( - errInvalidCounter = errors.New("invalid counter") -) - -// counter is a 96-bit, little-endian counter. -type counter struct { - value [counterLen]byte - invalid bool - overflowLen int -} - -// newOutCounter returns an outgoing counter initialized to the starting sequence +// NewOutCounter returns an outgoing counter initialized to the starting sequence // number for the client/server side of a connection. -func newOutCounter(s core.Side, overflowLen int) (c counter) { +func NewOutCounter(s core.Side, overflowLen int) (c Counter) { c.overflowLen = overflowLen if s == core.ServerSide { // Server counters in ALTS record have the little-endian high bit @@ -49,11 +32,11 @@ func newOutCounter(s core.Side, overflowLen int) (c counter) { return } -// newInCounter returns an incoming counter initialized to the starting sequence +// NewInCounter returns an incoming counter initialized to the starting sequence // number for the client/server side of a connection. This is used in ALTS record // to check that incoming counters are as expected, since ALTS record guarantees // that messages are unwrapped in the same order that the peer wrapped them. -func newInCounter(s core.Side, overflowLen int) (c counter) { +func NewInCounter(s core.Side, overflowLen int) (c Counter) { c.overflowLen = overflowLen if s == core.ClientSide { // Server counters in ALTS record have the little-endian high bit @@ -63,42 +46,16 @@ func newInCounter(s core.Side, overflowLen int) (c counter) { return } -// counterFromValue creates a new counter given an initial value. -func counterFromValue(value []byte, overflowLen int) (c counter) { +// CounterFromValue creates a new counter given an initial value. +func CounterFromValue(value []byte, overflowLen int) (c Counter) { c.overflowLen = overflowLen copy(c.value[:], value) return } -// Value returns the current value of the counter as a byte slice. -func (c *counter) Value() ([]byte, error) { - if c.invalid { - return nil, errInvalidCounter - } - return c.value[:], nil -} - -// Inc increments the counter and checks for overflow. -func (c *counter) Inc() { - // If the counter is already invalid, there is not need to increase it. - if c.invalid { - return - } - i := 0 - for ; i < c.overflowLen; i++ { - c.value[i]++ - if c.value[i] != 0 { - break - } - } - if i == c.overflowLen { - c.invalid = true - } -} - -// counterSide returns the connection side (client/server) a sequence counter is +// CounterSide returns the connection side (client/server) a sequence counter is // associated with. -func counterSide(c []byte) core.Side { +func CounterSide(c []byte) core.Side { if c[counterLen-1]&0x80 == 0x80 { return core.ServerSide } diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/handshaker/handshaker.go b/vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/handshaker.go similarity index 97% rename from vendor/google.golang.org/grpc/credentials/alts/core/handshaker/handshaker.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/handshaker.go index a204978517ed65689bdac07824a8dab5e44fe96f..82a1c9c58b581738f49fce9be0036d64835f4fae 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/core/handshaker/handshaker.go +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/handshaker.go @@ -20,21 +20,21 @@ package handshaker import ( + "context" "errors" "fmt" "io" "net" "sync" - "golang.org/x/net/context" grpc "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" - "google.golang.org/grpc/credentials/alts/core" - "google.golang.org/grpc/credentials/alts/core/authinfo" - "google.golang.org/grpc/credentials/alts/core/conn" - altsgrpc "google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp" - altspb "google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp" + core "google.golang.org/grpc/credentials/alts/internal" + "google.golang.org/grpc/credentials/alts/internal/authinfo" + "google.golang.org/grpc/credentials/alts/internal/conn" + altsgrpc "google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp" + altspb "google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp" ) const ( diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/handshaker/handshaker_test.go b/vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/handshaker_test.go similarity index 96% rename from vendor/google.golang.org/grpc/credentials/alts/core/handshaker/handshaker_test.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/handshaker_test.go index 322fcb4de77b1abf80c971463889b10543b44321..7608f53b7883d3f89c6f0d2667662a54bfad1201 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/core/handshaker/handshaker_test.go +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/handshaker_test.go @@ -20,14 +20,14 @@ package handshaker import ( "bytes" + "context" "testing" "time" - "golang.org/x/net/context" grpc "google.golang.org/grpc" - "google.golang.org/grpc/credentials/alts/core" - altspb "google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp" - "google.golang.org/grpc/credentials/alts/core/testutil" + core "google.golang.org/grpc/credentials/alts/internal" + altspb "google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp" + "google.golang.org/grpc/credentials/alts/internal/testutil" ) var ( @@ -89,8 +89,8 @@ func (t *testRPCStream) Send(req *altspb.HandshakerReq) error { } } else { // Add delay to test concurrent calls. - close := stat.Update() - defer close() + cleanup := stat.Update() + defer cleanup() time.Sleep(t.delay) // Generate the response to be returned by Recv() for the diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/handshaker/service/service.go b/vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/service/service.go similarity index 100% rename from vendor/google.golang.org/grpc/credentials/alts/core/handshaker/service/service.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/service/service.go diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/handshaker/service/service_test.go b/vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/service/service_test.go similarity index 100% rename from vendor/google.golang.org/grpc/credentials/alts/core/handshaker/service/service_test.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/service/service_test.go diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp/altscontext.pb.go b/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/altscontext.pb.go similarity index 50% rename from vendor/google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp/altscontext.pb.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/altscontext.pb.go index cd4fe79bbf226c50540c28dead73601c41c29072..d1793073ded191e657dc46d8a1a09cc75f0ec22f 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp/altscontext.pb.go +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/altscontext.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // source: grpc/gcp/altscontext.proto -package grpc_gcp // import "google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp" +package grpc_gcp // import "google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp" import proto "github.com/golang/protobuf/proto" import fmt "fmt" @@ -30,17 +30,19 @@ type AltsContext struct { // The local service account. LocalServiceAccount string `protobuf:"bytes,5,opt,name=local_service_account,json=localServiceAccount,proto3" json:"local_service_account,omitempty"` // The RPC protocol versions supported by the peer. - PeerRpcVersions *RpcProtocolVersions `protobuf:"bytes,6,opt,name=peer_rpc_versions,json=peerRpcVersions,proto3" json:"peer_rpc_versions,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + PeerRpcVersions *RpcProtocolVersions `protobuf:"bytes,6,opt,name=peer_rpc_versions,json=peerRpcVersions,proto3" json:"peer_rpc_versions,omitempty"` + // Additional attributes of the peer. + PeerAttributes map[string]string `protobuf:"bytes,7,rep,name=peer_attributes,json=peerAttributes,proto3" json:"peer_attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *AltsContext) Reset() { *m = AltsContext{} } func (m *AltsContext) String() string { return proto.CompactTextString(m) } func (*AltsContext) ProtoMessage() {} func (*AltsContext) Descriptor() ([]byte, []int) { - return fileDescriptor_altscontext_2f63c0ac7e856743, []int{0} + return fileDescriptor_altscontext_f6b7868f9a30497f, []int{0} } func (m *AltsContext) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_AltsContext.Unmarshal(m, b) @@ -102,36 +104,48 @@ func (m *AltsContext) GetPeerRpcVersions() *RpcProtocolVersions { return nil } +func (m *AltsContext) GetPeerAttributes() map[string]string { + if m != nil { + return m.PeerAttributes + } + return nil +} + func init() { proto.RegisterType((*AltsContext)(nil), "grpc.gcp.AltsContext") + proto.RegisterMapType((map[string]string)(nil), "grpc.gcp.AltsContext.PeerAttributesEntry") } func init() { - proto.RegisterFile("grpc/gcp/altscontext.proto", fileDescriptor_altscontext_2f63c0ac7e856743) -} - -var fileDescriptor_altscontext_2f63c0ac7e856743 = []byte{ - // 338 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0x4d, 0x4b, 0x23, 0x41, - 0x10, 0x86, 0x99, 0xec, 0x6e, 0xd8, 0xed, 0xb0, 0xc9, 0xee, 0x6c, 0xc2, 0x0e, 0x01, 0x21, 0x78, - 0x71, 0x4e, 0x33, 0x1a, 0x8f, 0x82, 0x90, 0x78, 0x12, 0x3c, 0x84, 0x09, 0x78, 0xf0, 0x32, 0xb4, - 0x95, 0xa2, 0x6d, 0xe8, 0x74, 0x35, 0xd5, 0x9d, 0xa0, 0x7f, 0xd5, 0x5f, 0x23, 0xd3, 0x93, 0x2f, - 0xf4, 0x58, 0xf5, 0xbc, 0x6f, 0x7d, 0x8a, 0xb1, 0x62, 0x07, 0xa5, 0x02, 0x57, 0x4a, 0x13, 0x3c, - 0x90, 0x0d, 0xf8, 0x1a, 0x0a, 0xc7, 0x14, 0x28, 0xfd, 0xd9, 0xb0, 0x42, 0x81, 0x1b, 0xe7, 0x07, - 0x55, 0x60, 0x69, 0xbd, 0x23, 0x0e, 0xb5, 0x47, 0xd8, 0xb0, 0x0e, 0x6f, 0x35, 0xd0, 0x7a, 0x4d, - 0xb6, 0xf5, 0x9c, 0xbf, 0x77, 0x44, 0x6f, 0x66, 0x82, 0xbf, 0x6b, 0x2b, 0xa5, 0x57, 0x62, 0x28, - 0x9d, 0x33, 0x1a, 0x64, 0xd0, 0x64, 0xeb, 0x28, 0x02, 0x32, 0x59, 0x32, 0x49, 0xf2, 0x5f, 0xd5, - 0xbf, 0x13, 0xb6, 0xd8, 0xa1, 0xf4, 0x42, 0x0c, 0x18, 0x81, 0x78, 0x75, 0x54, 0x77, 0xa2, 0xba, - 0xdf, 0xa6, 0x0f, 0xc2, 0x5b, 0xd1, 0x3f, 0x0c, 0x61, 0x70, 0x8b, 0x26, 0xfb, 0x36, 0x49, 0xf2, - 0xfe, 0xf4, 0x7f, 0xb1, 0x1f, 0xbc, 0x58, 0xee, 0xf8, 0x43, 0x83, 0xab, 0xdf, 0xfe, 0x34, 0x4c, - 0x2f, 0xc5, 0xd0, 0x21, 0x72, 0xed, 0x91, 0xb7, 0x1a, 0xb0, 0x96, 0x00, 0xb4, 0xb1, 0x21, 0xfb, - 0x1e, 0xbb, 0xa5, 0x0d, 0x5b, 0xb6, 0x68, 0xd6, 0x92, 0x74, 0x2a, 0x46, 0x86, 0x40, 0x9a, 0x2f, - 0x96, 0x1f, 0xed, 0x3a, 0x11, 0x7e, 0xf2, 0xdc, 0x8b, 0xbf, 0xb1, 0x0b, 0x3b, 0xa8, 0xb7, 0xc8, - 0x5e, 0x93, 0xf5, 0x59, 0x77, 0x92, 0xe4, 0xbd, 0xe9, 0xd9, 0x71, 0xd0, 0xca, 0xc1, 0x7e, 0xaf, - 0xc7, 0x9d, 0xa8, 0x1a, 0x34, 0xbe, 0xca, 0xc1, 0x3e, 0x31, 0x7f, 0x11, 0x23, 0x4d, 0xad, 0xa7, - 0xf9, 0x56, 0xa1, 0x6d, 0x40, 0xb6, 0xd2, 0xcc, 0xff, 0x9c, 0x9c, 0x3c, 0x96, 0x59, 0x24, 0x4f, - 0x37, 0x8a, 0x48, 0x19, 0x2c, 0x14, 0x19, 0x69, 0x55, 0x41, 0xac, 0xca, 0xf8, 0x45, 0x60, 0x5c, - 0xa1, 0x0d, 0x5a, 0x1a, 0x1f, 0x7f, 0x5e, 0x02, 0x31, 0x96, 0xf1, 0xd4, 0x51, 0x50, 0x2b, 0x70, - 0xcf, 0xdd, 0x18, 0x5f, 0x7f, 0x04, 0x00, 0x00, 0xff, 0xff, 0xe8, 0x41, 0xe3, 0x52, 0x1f, 0x02, - 0x00, 0x00, + proto.RegisterFile("grpc/gcp/altscontext.proto", fileDescriptor_altscontext_f6b7868f9a30497f) +} + +var fileDescriptor_altscontext_f6b7868f9a30497f = []byte{ + // 411 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x92, 0x4d, 0x6f, 0x13, 0x31, + 0x10, 0x86, 0xb5, 0x0d, 0x2d, 0xe0, 0x88, 0xb4, 0xb8, 0xa9, 0x58, 0x45, 0x42, 0x8a, 0xb8, 0xb0, + 0x5c, 0x76, 0x21, 0x5c, 0x10, 0x07, 0x50, 0x8a, 0x38, 0x20, 0x71, 0x88, 0xb6, 0x12, 0x07, 0x2e, + 0x2b, 0x77, 0x3a, 0xb2, 0x2c, 0x5c, 0x8f, 0x35, 0x76, 0x22, 0xf2, 0xb3, 0xf9, 0x07, 0x68, 0xed, + 0xcd, 0x07, 0x1f, 0xb7, 0x9d, 0x79, 0x9f, 0x19, 0xbf, 0xb3, 0x33, 0x62, 0xa6, 0xd9, 0x43, 0xa3, + 0xc1, 0x37, 0xca, 0xc6, 0x00, 0xe4, 0x22, 0xfe, 0x8c, 0xb5, 0x67, 0x8a, 0x24, 0x1f, 0xf5, 0x5a, + 0xad, 0xc1, 0xcf, 0xaa, 0x3d, 0x15, 0x59, 0xb9, 0xe0, 0x89, 0x63, 0x17, 0x10, 0xd6, 0x6c, 0xe2, + 0xb6, 0x03, 0xba, 0xbf, 0x27, 0x97, 0x6b, 0x5e, 0xfc, 0x1a, 0x89, 0xf1, 0xd2, 0xc6, 0xf0, 0x29, + 0x77, 0x92, 0x6f, 0xc4, 0x54, 0x79, 0x6f, 0x0d, 0xa8, 0x68, 0xc8, 0x75, 0x09, 0x02, 0xb2, 0x65, + 0x31, 0x2f, 0xaa, 0xc7, 0xed, 0xe5, 0x91, 0xb6, 0x1a, 0x24, 0xf9, 0x52, 0x9c, 0x33, 0x02, 0xf1, + 0xdd, 0x81, 0x3e, 0x49, 0xf4, 0x24, 0xa7, 0xf7, 0xe0, 0x07, 0x31, 0xd9, 0x9b, 0xb0, 0xb8, 0x41, + 0x5b, 0x8e, 0xe6, 0x45, 0x35, 0x59, 0x3c, 0xab, 0x77, 0xc6, 0xeb, 0x9b, 0x41, 0xff, 0xda, 0xcb, + 0xed, 0x93, 0x70, 0x1c, 0xca, 0xd7, 0x62, 0xea, 0x11, 0xb9, 0x0b, 0xc8, 0x1b, 0x03, 0xd8, 0x29, + 0x00, 0x5a, 0xbb, 0x58, 0x3e, 0x48, 0xaf, 0xc9, 0x5e, 0xbb, 0xc9, 0xd2, 0x32, 0x2b, 0x72, 0x21, + 0xae, 0x2c, 0x81, 0xb2, 0xff, 0x94, 0x9c, 0xe6, 0x71, 0x92, 0xf8, 0x57, 0xcd, 0x17, 0xf1, 0x34, + 0xbd, 0xc2, 0x1e, 0xba, 0x0d, 0x72, 0x30, 0xe4, 0x42, 0x79, 0x36, 0x2f, 0xaa, 0xf1, 0xe2, 0xf9, + 0xc1, 0x68, 0xeb, 0x61, 0x37, 0xd7, 0xb7, 0x01, 0x6a, 0xcf, 0xfb, 0xba, 0xd6, 0xc3, 0x2e, 0x21, + 0x5b, 0x91, 0x52, 0x9d, 0x8a, 0x91, 0xcd, 0xed, 0x3a, 0x62, 0x28, 0x1f, 0xce, 0x47, 0xd5, 0x78, + 0xf1, 0xea, 0xd0, 0xe8, 0xe8, 0xe7, 0xd7, 0x2b, 0x44, 0x5e, 0xee, 0xd9, 0xcf, 0x2e, 0xf2, 0xb6, + 0x9d, 0xf8, 0x3f, 0x92, 0xb3, 0xa5, 0xb8, 0xfc, 0x0f, 0x26, 0x2f, 0xc4, 0xe8, 0x07, 0x6e, 0x87, + 0x35, 0xf5, 0x9f, 0x72, 0x2a, 0x4e, 0x37, 0xca, 0xae, 0x71, 0x58, 0x46, 0x0e, 0xde, 0x9f, 0xbc, + 0x2b, 0xae, 0xad, 0xb8, 0x32, 0x94, 0x1d, 0xf4, 0x47, 0x54, 0x1b, 0x17, 0x91, 0x9d, 0xb2, 0xd7, + 0x17, 0x47, 0x66, 0xd2, 0x74, 0xab, 0xe2, 0xfb, 0x47, 0x4d, 0xa4, 0x2d, 0xd6, 0x9a, 0xac, 0x72, + 0xba, 0x26, 0xd6, 0x4d, 0x3a, 0x2e, 0x60, 0xbc, 0x43, 0x17, 0x8d, 0xb2, 0x21, 0x9d, 0x62, 0xb3, + 0xeb, 0xd2, 0xa4, 0x2b, 0x48, 0x50, 0xa7, 0xc1, 0xdf, 0x9e, 0xa5, 0xf8, 0xed, 0xef, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x9b, 0x8c, 0xe4, 0x6a, 0xba, 0x02, 0x00, 0x00, } diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp/handshaker.pb.go b/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/handshaker.pb.go similarity index 81% rename from vendor/google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp/handshaker.pb.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/handshaker.pb.go index 01e87194b47a8cd47e6afba5dd4a39ba56a24d68..0c37ba2abebb0411212ed4bc183cb4c03fca32c0 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp/handshaker.pb.go +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/handshaker.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // source: grpc/gcp/handshaker.proto -package grpc_gcp // import "google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp" +package grpc_gcp // import "google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp" import proto "github.com/golang/protobuf/proto" import fmt "fmt" @@ -41,15 +41,15 @@ var HandshakeProtocol_name = map[int32]string{ } var HandshakeProtocol_value = map[string]int32{ "HANDSHAKE_PROTOCOL_UNSPECIFIED": 0, - "TLS": 1, - "ALTS": 2, + "TLS": 1, + "ALTS": 2, } func (x HandshakeProtocol) String() string { return proto.EnumName(HandshakeProtocol_name, int32(x)) } func (HandshakeProtocol) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_handshaker_b28e45bdd1661054, []int{0} + return fileDescriptor_handshaker_1dfe659b12ea825e, []int{0} } type NetworkProtocol int32 @@ -67,15 +67,15 @@ var NetworkProtocol_name = map[int32]string{ } var NetworkProtocol_value = map[string]int32{ "NETWORK_PROTOCOL_UNSPECIFIED": 0, - "TCP": 1, - "UDP": 2, + "TCP": 1, + "UDP": 2, } func (x NetworkProtocol) String() string { return proto.EnumName(NetworkProtocol_name, int32(x)) } func (NetworkProtocol) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_handshaker_b28e45bdd1661054, []int{1} + return fileDescriptor_handshaker_1dfe659b12ea825e, []int{1} } type Endpoint struct { @@ -95,7 +95,7 @@ func (m *Endpoint) Reset() { *m = Endpoint{} } func (m *Endpoint) String() string { return proto.CompactTextString(m) } func (*Endpoint) ProtoMessage() {} func (*Endpoint) Descriptor() ([]byte, []int) { - return fileDescriptor_handshaker_b28e45bdd1661054, []int{0} + return fileDescriptor_handshaker_1dfe659b12ea825e, []int{0} } func (m *Endpoint) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Endpoint.Unmarshal(m, b) @@ -140,17 +140,19 @@ type Identity struct { // Types that are valid to be assigned to IdentityOneof: // *Identity_ServiceAccount // *Identity_Hostname - IdentityOneof isIdentity_IdentityOneof `protobuf_oneof:"identity_oneof"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + IdentityOneof isIdentity_IdentityOneof `protobuf_oneof:"identity_oneof"` + // Additional attributes of the identity. + Attributes map[string]string `protobuf:"bytes,3,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Identity) Reset() { *m = Identity{} } func (m *Identity) String() string { return proto.CompactTextString(m) } func (*Identity) ProtoMessage() {} func (*Identity) Descriptor() ([]byte, []int) { - return fileDescriptor_handshaker_b28e45bdd1661054, []int{1} + return fileDescriptor_handshaker_1dfe659b12ea825e, []int{1} } func (m *Identity) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Identity.Unmarshal(m, b) @@ -177,12 +179,14 @@ type isIdentity_IdentityOneof interface { type Identity_ServiceAccount struct { ServiceAccount string `protobuf:"bytes,1,opt,name=service_account,json=serviceAccount,proto3,oneof"` } + type Identity_Hostname struct { Hostname string `protobuf:"bytes,2,opt,name=hostname,proto3,oneof"` } func (*Identity_ServiceAccount) isIdentity_IdentityOneof() {} -func (*Identity_Hostname) isIdentity_IdentityOneof() {} + +func (*Identity_Hostname) isIdentity_IdentityOneof() {} func (m *Identity) GetIdentityOneof() isIdentity_IdentityOneof { if m != nil { @@ -205,6 +209,13 @@ func (m *Identity) GetHostname() string { return "" } +func (m *Identity) GetAttributes() map[string]string { + if m != nil { + return m.Attributes + } + return nil +} + // XXX_OneofFuncs is for the internal use of the proto package. func (*Identity) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { return _Identity_OneofMarshaler, _Identity_OneofUnmarshaler, _Identity_OneofSizer, []interface{}{ @@ -308,7 +319,7 @@ func (m *StartClientHandshakeReq) Reset() { *m = StartClientHandshakeReq func (m *StartClientHandshakeReq) String() string { return proto.CompactTextString(m) } func (*StartClientHandshakeReq) ProtoMessage() {} func (*StartClientHandshakeReq) Descriptor() ([]byte, []int) { - return fileDescriptor_handshaker_b28e45bdd1661054, []int{2} + return fileDescriptor_handshaker_1dfe659b12ea825e, []int{2} } func (m *StartClientHandshakeReq) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StartClientHandshakeReq.Unmarshal(m, b) @@ -407,7 +418,7 @@ func (m *ServerHandshakeParameters) Reset() { *m = ServerHandshakeParame func (m *ServerHandshakeParameters) String() string { return proto.CompactTextString(m) } func (*ServerHandshakeParameters) ProtoMessage() {} func (*ServerHandshakeParameters) Descriptor() ([]byte, []int) { - return fileDescriptor_handshaker_b28e45bdd1661054, []int{3} + return fileDescriptor_handshaker_1dfe659b12ea825e, []int{3} } func (m *ServerHandshakeParameters) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ServerHandshakeParameters.Unmarshal(m, b) @@ -471,7 +482,7 @@ func (m *StartServerHandshakeReq) Reset() { *m = StartServerHandshakeReq func (m *StartServerHandshakeReq) String() string { return proto.CompactTextString(m) } func (*StartServerHandshakeReq) ProtoMessage() {} func (*StartServerHandshakeReq) Descriptor() ([]byte, []int) { - return fileDescriptor_handshaker_b28e45bdd1661054, []int{4} + return fileDescriptor_handshaker_1dfe659b12ea825e, []int{4} } func (m *StartServerHandshakeReq) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StartServerHandshakeReq.Unmarshal(m, b) @@ -547,7 +558,7 @@ func (m *NextHandshakeMessageReq) Reset() { *m = NextHandshakeMessageReq func (m *NextHandshakeMessageReq) String() string { return proto.CompactTextString(m) } func (*NextHandshakeMessageReq) ProtoMessage() {} func (*NextHandshakeMessageReq) Descriptor() ([]byte, []int) { - return fileDescriptor_handshaker_b28e45bdd1661054, []int{5} + return fileDescriptor_handshaker_1dfe659b12ea825e, []int{5} } func (m *NextHandshakeMessageReq) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NextHandshakeMessageReq.Unmarshal(m, b) @@ -589,7 +600,7 @@ func (m *HandshakerReq) Reset() { *m = HandshakerReq{} } func (m *HandshakerReq) String() string { return proto.CompactTextString(m) } func (*HandshakerReq) ProtoMessage() {} func (*HandshakerReq) Descriptor() ([]byte, []int) { - return fileDescriptor_handshaker_b28e45bdd1661054, []int{6} + return fileDescriptor_handshaker_1dfe659b12ea825e, []int{6} } func (m *HandshakerReq) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_HandshakerReq.Unmarshal(m, b) @@ -616,16 +627,20 @@ type isHandshakerReq_ReqOneof interface { type HandshakerReq_ClientStart struct { ClientStart *StartClientHandshakeReq `protobuf:"bytes,1,opt,name=client_start,json=clientStart,proto3,oneof"` } + type HandshakerReq_ServerStart struct { ServerStart *StartServerHandshakeReq `protobuf:"bytes,2,opt,name=server_start,json=serverStart,proto3,oneof"` } + type HandshakerReq_Next struct { Next *NextHandshakeMessageReq `protobuf:"bytes,3,opt,name=next,proto3,oneof"` } func (*HandshakerReq_ClientStart) isHandshakerReq_ReqOneof() {} + func (*HandshakerReq_ServerStart) isHandshakerReq_ReqOneof() {} -func (*HandshakerReq_Next) isHandshakerReq_ReqOneof() {} + +func (*HandshakerReq_Next) isHandshakerReq_ReqOneof() {} func (m *HandshakerReq) GetReqOneof() isHandshakerReq_ReqOneof { if m != nil { @@ -776,7 +791,7 @@ func (m *HandshakerResult) Reset() { *m = HandshakerResult{} } func (m *HandshakerResult) String() string { return proto.CompactTextString(m) } func (*HandshakerResult) ProtoMessage() {} func (*HandshakerResult) Descriptor() ([]byte, []int) { - return fileDescriptor_handshaker_b28e45bdd1661054, []int{7} + return fileDescriptor_handshaker_1dfe659b12ea825e, []int{7} } func (m *HandshakerResult) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_HandshakerResult.Unmarshal(m, b) @@ -859,7 +874,7 @@ func (m *HandshakerStatus) Reset() { *m = HandshakerStatus{} } func (m *HandshakerStatus) String() string { return proto.CompactTextString(m) } func (*HandshakerStatus) ProtoMessage() {} func (*HandshakerStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_handshaker_b28e45bdd1661054, []int{8} + return fileDescriptor_handshaker_1dfe659b12ea825e, []int{8} } func (m *HandshakerStatus) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_HandshakerStatus.Unmarshal(m, b) @@ -918,7 +933,7 @@ func (m *HandshakerResp) Reset() { *m = HandshakerResp{} } func (m *HandshakerResp) String() string { return proto.CompactTextString(m) } func (*HandshakerResp) ProtoMessage() {} func (*HandshakerResp) Descriptor() ([]byte, []int) { - return fileDescriptor_handshaker_b28e45bdd1661054, []int{9} + return fileDescriptor_handshaker_1dfe659b12ea825e, []int{9} } func (m *HandshakerResp) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_HandshakerResp.Unmarshal(m, b) @@ -969,6 +984,7 @@ func (m *HandshakerResp) GetStatus() *HandshakerStatus { func init() { proto.RegisterType((*Endpoint)(nil), "grpc.gcp.Endpoint") proto.RegisterType((*Identity)(nil), "grpc.gcp.Identity") + proto.RegisterMapType((map[string]string)(nil), "grpc.gcp.Identity.AttributesEntry") proto.RegisterType((*StartClientHandshakeReq)(nil), "grpc.gcp.StartClientHandshakeReq") proto.RegisterType((*ServerHandshakeParameters)(nil), "grpc.gcp.ServerHandshakeParameters") proto.RegisterType((*StartServerHandshakeReq)(nil), "grpc.gcp.StartServerHandshakeReq") @@ -1099,80 +1115,82 @@ var _HandshakerService_serviceDesc = grpc.ServiceDesc{ } func init() { - proto.RegisterFile("grpc/gcp/handshaker.proto", fileDescriptor_handshaker_b28e45bdd1661054) + proto.RegisterFile("grpc/gcp/handshaker.proto", fileDescriptor_handshaker_1dfe659b12ea825e) } -var fileDescriptor_handshaker_b28e45bdd1661054 = []byte{ - // 1128 bytes of a gzipped FileDescriptorProto +var fileDescriptor_handshaker_1dfe659b12ea825e = []byte{ + // 1168 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0xdf, 0x6e, 0x1a, 0xc7, - 0x17, 0xf6, 0x02, 0xb6, 0xe1, 0x60, 0xfe, 0x78, 0x92, 0x28, 0xd8, 0x49, 0x7e, 0x3f, 0x4a, 0x55, - 0x95, 0xf8, 0x02, 0x5a, 0xd2, 0x2a, 0x4d, 0xa2, 0xaa, 0xb1, 0x31, 0x16, 0x6e, 0x5c, 0x8c, 0x16, - 0xa7, 0x95, 0x9a, 0x8b, 0xd5, 0x64, 0x39, 0x59, 0xaf, 0x58, 0x66, 0xd6, 0x33, 0x83, 0x1b, 0x1e, - 0xa0, 0x8f, 0xd3, 0x57, 0xe8, 0xdb, 0xf4, 0x0d, 0x7a, 0xdf, 0x6a, 0x67, 0xff, 0x61, 0x0c, 0x51, - 0xa2, 0xde, 0xed, 0xce, 0x7c, 0xdf, 0xd9, 0x73, 0xbe, 0xf3, 0xcd, 0xd9, 0x81, 0x3d, 0x47, 0xf8, - 0x76, 0xdb, 0xb1, 0xfd, 0xf6, 0x25, 0x65, 0x63, 0x79, 0x49, 0x27, 0x28, 0x5a, 0xbe, 0xe0, 0x8a, - 0x93, 0x7c, 0xb0, 0xd5, 0x72, 0x6c, 0x7f, 0xbf, 0x99, 0x80, 0x94, 0xa0, 0x4c, 0xfa, 0x5c, 0x28, - 0x4b, 0xa2, 0x3d, 0x13, 0xae, 0x9a, 0x5b, 0x36, 0x9f, 0x4e, 0x39, 0x0b, 0x39, 0x0d, 0x05, 0xf9, - 0x1e, 0x1b, 0xfb, 0xdc, 0x65, 0x8a, 0x3c, 0x02, 0x70, 0x7d, 0x8b, 0x8e, 0xc7, 0x02, 0xa5, 0xac, - 0x19, 0x75, 0xa3, 0x59, 0x30, 0x0b, 0xae, 0x7f, 0x18, 0x2e, 0x10, 0x02, 0xb9, 0x20, 0x50, 0x2d, - 0x53, 0x37, 0x9a, 0x9b, 0xa6, 0x7e, 0x26, 0xdf, 0x42, 0x5e, 0xc7, 0xb1, 0xb9, 0x57, 0xcb, 0xd6, - 0x8d, 0x66, 0xb9, 0xb3, 0xd7, 0x8a, 0xb3, 0x68, 0x0d, 0x50, 0xfd, 0xc6, 0xc5, 0x64, 0x18, 0x01, - 0xcc, 0x04, 0xda, 0x40, 0xc8, 0x9f, 0x8e, 0x91, 0x29, 0x57, 0xcd, 0xc9, 0x63, 0xa8, 0x48, 0x14, - 0xd7, 0xae, 0x8d, 0x16, 0xb5, 0x6d, 0x3e, 0x63, 0x2a, 0xfc, 0x74, 0x7f, 0xc3, 0x2c, 0x47, 0x1b, - 0x87, 0xe1, 0x3a, 0x79, 0x08, 0xf9, 0x4b, 0x2e, 0x15, 0xa3, 0x53, 0xd4, 0x59, 0x04, 0x98, 0x64, - 0xe5, 0xa8, 0x0a, 0x65, 0x37, 0x0a, 0x6a, 0x71, 0x86, 0xfc, 0x5d, 0xe3, 0x8f, 0x1c, 0xdc, 0x1f, - 0x29, 0x2a, 0x54, 0xd7, 0x73, 0x91, 0xa9, 0x7e, 0x2c, 0x98, 0x89, 0x57, 0xe4, 0x0d, 0x3c, 0x48, - 0x04, 0x4c, 0xb5, 0x49, 0x8a, 0x31, 0x74, 0x31, 0x0f, 0xd2, 0x62, 0x12, 0x72, 0x52, 0xce, 0x5e, - 0xc2, 0x1f, 0x45, 0xf4, 0x78, 0x8b, 0x3c, 0x81, 0x7b, 0xd4, 0xf7, 0x3d, 0xd7, 0xa6, 0xca, 0xe5, - 0x2c, 0x89, 0x2a, 0x6b, 0x99, 0x7a, 0xb6, 0x59, 0x30, 0xef, 0x2e, 0x6c, 0xc6, 0x1c, 0x49, 0x1e, - 0x43, 0x55, 0xa0, 0xcd, 0xc5, 0x78, 0x01, 0x9f, 0xd5, 0xf8, 0x4a, 0xb8, 0x9e, 0x42, 0x7f, 0x80, - 0x5d, 0x45, 0x85, 0x83, 0xca, 0x8a, 0x2a, 0x76, 0x51, 0xd6, 0x72, 0xf5, 0x6c, 0xb3, 0xd8, 0x21, - 0x69, 0xca, 0xb1, 0xc4, 0x66, 0x35, 0x04, 0x9f, 0x26, 0x58, 0xf2, 0x0c, 0xca, 0x1e, 0xb7, 0xa9, - 0x17, 0xf3, 0xe7, 0xb5, 0xcd, 0xba, 0xb1, 0x86, 0x5d, 0xd2, 0xc8, 0xa4, 0x5f, 0x09, 0x15, 0x23, - 0xdf, 0xd4, 0xb6, 0x96, 0xa9, 0xb1, 0xa3, 0x22, 0x6a, 0x62, 0xb0, 0x17, 0x50, 0x11, 0x38, 0xe5, - 0x0a, 0x53, 0xee, 0xf6, 0x5a, 0x6e, 0x39, 0x84, 0x26, 0xe4, 0xff, 0x43, 0x31, 0xaa, 0x59, 0xf7, - 0x3f, 0xaf, 0xed, 0x09, 0xe1, 0xd2, 0x80, 0x4e, 0x91, 0xbc, 0x84, 0x1d, 0xe1, 0xdb, 0xd6, 0x35, - 0x0a, 0xe9, 0x72, 0x26, 0x6b, 0x05, 0x1d, 0xfa, 0x51, 0x1a, 0xda, 0xf4, 0xed, 0x58, 0xc2, 0x9f, - 0x23, 0x90, 0x59, 0x14, 0xbe, 0x1d, 0xbf, 0x34, 0x7e, 0x37, 0x60, 0x6f, 0x84, 0xe2, 0x1a, 0x45, - 0xda, 0x6d, 0x2a, 0xe8, 0x14, 0x15, 0x8a, 0xd5, 0xfd, 0x31, 0x56, 0xf7, 0xe7, 0x7b, 0xa8, 0xde, - 0x90, 0x37, 0x68, 0x4f, 0x66, 0x6d, 0x7b, 0x2a, 0x8b, 0x02, 0xbb, 0x28, 0x1b, 0xff, 0x64, 0x23, - 0xdf, 0x2e, 0x25, 0x13, 0xf8, 0x76, 0xad, 0xb5, 0x8c, 0x0f, 0x58, 0x6b, 0x0a, 0x77, 0x53, 0xb3, - 0xfb, 0x49, 0x49, 0x51, 0x4e, 0xcf, 0xd3, 0x9c, 0xd6, 0x7c, 0xb5, 0xb5, 0x42, 0x8f, 0x1e, 0x53, - 0x62, 0x6e, 0xde, 0xb9, 0x5c, 0xa1, 0xd4, 0x1e, 0xe4, 0x5d, 0x66, 0xbd, 0x9d, 0x2b, 0x94, 0x7a, - 0x2a, 0xec, 0x98, 0xdb, 0x2e, 0x3b, 0x0a, 0x5e, 0x57, 0xb8, 0x27, 0xf7, 0x1f, 0xdc, 0xb3, 0xf9, - 0xd1, 0xee, 0x59, 0x36, 0xc7, 0xd6, 0xa7, 0x9a, 0x63, 0x7f, 0x02, 0xb5, 0x75, 0x2a, 0x90, 0x2a, - 0x64, 0x27, 0x38, 0xd7, 0x43, 0x63, 0xd3, 0x0c, 0x1e, 0xc9, 0x33, 0xd8, 0xbc, 0xa6, 0xde, 0x2c, - 0x9c, 0x53, 0xc5, 0xce, 0xe7, 0x0b, 0x12, 0xaf, 0x33, 0x98, 0x19, 0x32, 0x9e, 0x67, 0xbe, 0x33, - 0x1a, 0xdf, 0xc0, 0xfd, 0x01, 0xbe, 0x4f, 0x27, 0xd6, 0x4f, 0x28, 0x25, 0x75, 0xb4, 0x01, 0x16, - 0xc5, 0x35, 0x6e, 0x88, 0xdb, 0xf8, 0xcb, 0x80, 0x52, 0x42, 0x11, 0x01, 0xf8, 0x04, 0x76, 0x6c, - 0x3d, 0xfb, 0x2c, 0x19, 0x74, 0x56, 0x13, 0x8a, 0x9d, 0xcf, 0x96, 0x1a, 0x7e, 0x7b, 0x3c, 0xf6, - 0x37, 0xcc, 0x62, 0x48, 0xd4, 0x80, 0x20, 0x8e, 0xd4, 0x79, 0x47, 0x71, 0x32, 0x2b, 0xe3, 0xdc, - 0x36, 0x4e, 0x10, 0x27, 0x24, 0x86, 0x71, 0x9e, 0x42, 0x8e, 0xe1, 0x7b, 0xa5, 0x5d, 0x71, 0x83, - 0xbf, 0xa6, 0xda, 0xfe, 0x86, 0xa9, 0x09, 0x47, 0x45, 0x28, 0x08, 0xbc, 0x8a, 0xe6, 0xfa, 0xdf, - 0x19, 0xa8, 0x2e, 0xd6, 0x29, 0x67, 0x9e, 0x22, 0x5f, 0xc3, 0xdd, 0x55, 0x07, 0x23, 0xfa, 0x8f, - 0xdd, 0x59, 0x71, 0x2e, 0xc8, 0x97, 0x50, 0x59, 0x3a, 0xd1, 0xe1, 0x6f, 0x25, 0x70, 0xcf, 0xe2, - 0x81, 0x0e, 0x34, 0x9f, 0xe0, 0xdc, 0x1a, 0x53, 0x45, 0x63, 0x43, 0x4f, 0x70, 0x7e, 0x4c, 0x15, - 0x25, 0x4f, 0xa1, 0xe4, 0x23, 0x8a, 0x74, 0x90, 0xe6, 0xd6, 0x0e, 0xd2, 0x9d, 0x00, 0x78, 0x7b, - 0x8e, 0x7e, 0xfa, 0x08, 0x3e, 0x80, 0xdd, 0x09, 0xa2, 0x6f, 0xd9, 0x97, 0x94, 0x31, 0xf4, 0x2c, - 0xee, 0x23, 0xd3, 0x8e, 0xce, 0x9b, 0x95, 0x60, 0xa3, 0x1b, 0xae, 0x9f, 0xfb, 0xc8, 0xc8, 0x29, - 0xec, 0xea, 0xfc, 0x6e, 0xb8, 0x7f, 0xfb, 0x63, 0xdc, 0x5f, 0x09, 0x78, 0xe6, 0xc2, 0x78, 0x7c, - 0xb9, 0xa8, 0xfa, 0x48, 0x51, 0x35, 0xd3, 0x97, 0x02, 0x9b, 0x8f, 0x51, 0xab, 0x5c, 0x32, 0xf5, - 0x33, 0xa9, 0xc1, 0xf6, 0x18, 0x15, 0x75, 0xf5, 0xff, 0x2e, 0x90, 0x33, 0x7e, 0x6d, 0xfc, 0x69, - 0x40, 0xf9, 0x46, 0xe3, 0xfc, 0xe0, 0xd2, 0xc1, 0x67, 0xca, 0x7a, 0x17, 0x9c, 0x82, 0xd8, 0xd0, - 0x05, 0x3e, 0x53, 0x27, 0x7a, 0x81, 0x7c, 0x01, 0x65, 0x6d, 0x75, 0xcb, 0xe6, 0x4c, 0xce, 0xa6, - 0x38, 0xd6, 0x21, 0x4b, 0x66, 0x49, 0xaf, 0x76, 0xa3, 0x45, 0xd2, 0x81, 0x2d, 0xa1, 0x6d, 0x10, - 0x39, 0x6b, 0x7f, 0xc5, 0x8f, 0x3b, 0x32, 0x8a, 0x19, 0x21, 0x03, 0x8e, 0xd4, 0x45, 0x44, 0x2d, - 0x5b, 0xc9, 0x09, 0xcb, 0x34, 0x23, 0xe4, 0xc1, 0x8f, 0xb0, 0x7b, 0xeb, 0x22, 0x40, 0x1a, 0xf0, - 0xbf, 0xfe, 0xe1, 0xe0, 0x78, 0xd4, 0x3f, 0x7c, 0xd5, 0xb3, 0x86, 0xe6, 0xf9, 0xc5, 0x79, 0xf7, - 0xfc, 0xcc, 0x7a, 0x3d, 0x18, 0x0d, 0x7b, 0xdd, 0xd3, 0x93, 0xd3, 0xde, 0x71, 0x75, 0x83, 0x6c, - 0x43, 0xf6, 0xe2, 0x6c, 0x54, 0x35, 0x48, 0x1e, 0x72, 0x87, 0x67, 0x17, 0xa3, 0x6a, 0xe6, 0xa0, - 0x07, 0x95, 0xa5, 0x1b, 0x12, 0xa9, 0xc3, 0xc3, 0x41, 0xef, 0xe2, 0x97, 0x73, 0xf3, 0xd5, 0x87, - 0xe2, 0x74, 0x87, 0x55, 0x23, 0x78, 0x78, 0x7d, 0x3c, 0xac, 0x66, 0x3a, 0x6f, 0x16, 0x52, 0x12, - 0xa3, 0xf0, 0xc2, 0x44, 0x4e, 0xa0, 0x78, 0xcc, 0x93, 0x65, 0x72, 0x7f, 0xb5, 0x1c, 0x57, 0xfb, - 0xb5, 0x35, 0x3a, 0xf9, 0x8d, 0x8d, 0xa6, 0xf1, 0x95, 0x71, 0xe4, 0xc0, 0x3d, 0x97, 0x87, 0x18, - 0xea, 0x29, 0xd9, 0x72, 0x99, 0x42, 0xc1, 0xa8, 0x77, 0x54, 0x49, 0xe1, 0x3a, 0xfb, 0xa1, 0xf1, - 0xeb, 0x0b, 0x87, 0x73, 0xc7, 0xc3, 0x96, 0xc3, 0x3d, 0xca, 0x9c, 0x16, 0x17, 0x4e, 0x5b, 0x5f, - 0x43, 0x6d, 0x81, 0xda, 0xb8, 0xd4, 0x93, 0xed, 0x20, 0x48, 0xdb, 0xe6, 0x02, 0xdb, 0xfa, 0xc4, - 0x69, 0x80, 0xe5, 0xd8, 0xfe, 0xdb, 0x2d, 0xfd, 0xfe, 0xe4, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xfa, 0xd2, 0x42, 0x7f, 0xdf, 0x0a, 0x00, 0x00, + 0x17, 0xf6, 0x02, 0xb6, 0xf1, 0xc1, 0xfc, 0xf1, 0xc4, 0x51, 0xd6, 0x4e, 0xf2, 0xfb, 0x51, 0xaa, + 0xaa, 0x24, 0x17, 0xd0, 0x92, 0x56, 0x69, 0x52, 0x45, 0x09, 0x60, 0x2c, 0xdc, 0xa4, 0x18, 0x2d, + 0x4e, 0x2b, 0x35, 0x17, 0xab, 0xc9, 0x32, 0xc1, 0x2b, 0x96, 0x99, 0xf5, 0xcc, 0xe0, 0x86, 0x07, + 0xe8, 0xe3, 0xf4, 0x15, 0xfa, 0x36, 0x95, 0xfa, 0x00, 0xbd, 0x6f, 0xb5, 0xb3, 0xb3, 0x7f, 0xc0, + 0x10, 0x25, 0xea, 0xdd, 0xee, 0x99, 0xef, 0x3b, 0x7b, 0xe6, 0x3b, 0xdf, 0x9c, 0x1d, 0x38, 0x9a, + 0x70, 0xdf, 0x69, 0x4e, 0x1c, 0xbf, 0x79, 0x89, 0xe9, 0x58, 0x5c, 0xe2, 0x29, 0xe1, 0x0d, 0x9f, + 0x33, 0xc9, 0x50, 0x3e, 0x58, 0x6a, 0x4c, 0x1c, 0xff, 0xb8, 0x1e, 0x83, 0x24, 0xc7, 0x54, 0xf8, + 0x8c, 0x4b, 0x5b, 0x10, 0x67, 0xce, 0x5d, 0xb9, 0xb0, 0x1d, 0x36, 0x9b, 0x31, 0x1a, 0x72, 0x6a, + 0x12, 0xf2, 0x3d, 0x3a, 0xf6, 0x99, 0x4b, 0x25, 0xba, 0x0f, 0xe0, 0xfa, 0x36, 0x1e, 0x8f, 0x39, + 0x11, 0xc2, 0x34, 0xaa, 0x46, 0x7d, 0xcf, 0xda, 0x73, 0xfd, 0x76, 0x18, 0x40, 0x08, 0x72, 0x41, + 0x22, 0x33, 0x53, 0x35, 0xea, 0xdb, 0x96, 0x7a, 0x46, 0xdf, 0x42, 0x5e, 0xe5, 0x71, 0x98, 0x67, + 0x66, 0xab, 0x46, 0xbd, 0xd4, 0x3a, 0x6a, 0x44, 0x55, 0x34, 0x06, 0x44, 0xfe, 0xca, 0xf8, 0x74, + 0xa8, 0x01, 0x56, 0x0c, 0xad, 0xfd, 0x65, 0x40, 0xfe, 0x6c, 0x4c, 0xa8, 0x74, 0xe5, 0x02, 0x3d, + 0x80, 0xb2, 0x20, 0xfc, 0xda, 0x75, 0x88, 0x8d, 0x1d, 0x87, 0xcd, 0xa9, 0x0c, 0xbf, 0xdd, 0xdf, + 0xb2, 0x4a, 0x7a, 0xa1, 0x1d, 0xc6, 0xd1, 0x3d, 0xc8, 0x5f, 0x32, 0x21, 0x29, 0x9e, 0x11, 0x55, + 0x46, 0x80, 0x89, 0x23, 0xa8, 0x03, 0x80, 0xa5, 0xe4, 0xee, 0xdb, 0xb9, 0x24, 0xc2, 0xcc, 0x56, + 0xb3, 0xf5, 0x42, 0xab, 0x96, 0x94, 0x13, 0x7d, 0xb0, 0xd1, 0x8e, 0x41, 0x3d, 0x2a, 0xf9, 0xc2, + 0x4a, 0xb1, 0x8e, 0x9f, 0x41, 0x79, 0x65, 0x19, 0x55, 0x20, 0x3b, 0x25, 0x0b, 0xad, 0x47, 0xf0, + 0x88, 0x0e, 0x61, 0xfb, 0x1a, 0x7b, 0x73, 0x5d, 0x83, 0x15, 0xbe, 0x3c, 0xcd, 0x7c, 0x67, 0x74, + 0x2a, 0x50, 0x72, 0xf5, 0x67, 0x6c, 0x46, 0x09, 0x7b, 0x57, 0xfb, 0x3d, 0x07, 0x77, 0x46, 0x12, + 0x73, 0xd9, 0xf5, 0x5c, 0x42, 0x65, 0x3f, 0x6a, 0x9a, 0x45, 0xae, 0xd0, 0x1b, 0xb8, 0x1b, 0x37, + 0x31, 0xe9, 0x4f, 0x2c, 0xa8, 0xa1, 0x04, 0xbd, 0x9b, 0xec, 0x20, 0x26, 0xc7, 0x92, 0x1e, 0xc5, + 0xfc, 0x91, 0xa6, 0x47, 0x4b, 0xe8, 0x11, 0xdc, 0xc6, 0xbe, 0xef, 0xb9, 0x0e, 0x96, 0x2e, 0xa3, + 0x71, 0x56, 0x61, 0x66, 0xaa, 0xd9, 0xfa, 0x9e, 0x75, 0x98, 0x5a, 0x8c, 0x38, 0x02, 0x3d, 0x80, + 0x0a, 0x27, 0x0e, 0xe3, 0xe3, 0x14, 0x3e, 0xab, 0xf0, 0xe5, 0x30, 0x9e, 0x40, 0x9f, 0xc3, 0x81, + 0xc4, 0x7c, 0x42, 0xa4, 0xad, 0x77, 0xec, 0x12, 0x61, 0xe6, 0x94, 0xe8, 0xe8, 0xa6, 0xe8, 0x56, + 0x25, 0x04, 0x9f, 0xc5, 0x58, 0xf4, 0x04, 0x4a, 0x1e, 0x73, 0xb0, 0x17, 0xf1, 0x17, 0xe6, 0x76, + 0xd5, 0xd8, 0xc0, 0x2e, 0x2a, 0x64, 0x6c, 0x99, 0x98, 0x4a, 0xb4, 0x77, 0xcd, 0x9d, 0x55, 0x6a, + 0xe4, 0x6a, 0x4d, 0x8d, 0x4d, 0xfe, 0x3d, 0x94, 0x39, 0x99, 0x31, 0x49, 0x12, 0xee, 0xee, 0x46, + 0x6e, 0x29, 0x84, 0xc6, 0xe4, 0xff, 0x43, 0x41, 0xef, 0x59, 0x59, 0x30, 0xaf, 0xda, 0x0f, 0x61, + 0x68, 0x10, 0x58, 0xf0, 0x05, 0xec, 0x73, 0xdf, 0xb1, 0xaf, 0x09, 0x17, 0x2e, 0xa3, 0xc2, 0xdc, + 0x53, 0xa9, 0xef, 0x27, 0xa9, 0x2d, 0xdf, 0x89, 0x24, 0xfc, 0x49, 0x83, 0xac, 0x02, 0xf7, 0x9d, + 0xe8, 0xa5, 0xf6, 0x9b, 0x01, 0x47, 0x23, 0xc2, 0xaf, 0x09, 0x4f, 0xba, 0x8d, 0x39, 0x9e, 0x11, + 0x49, 0xf8, 0xfa, 0xfe, 0x18, 0xeb, 0xfb, 0xf3, 0x0c, 0x2a, 0x4b, 0xf2, 0x06, 0xed, 0xc9, 0x6c, + 0x6c, 0x4f, 0x39, 0x2d, 0xb0, 0x4b, 0x44, 0xed, 0x9f, 0xac, 0xf6, 0xed, 0x4a, 0x31, 0x81, 0x6f, + 0x37, 0x5a, 0xcb, 0xf8, 0x80, 0xb5, 0x66, 0x70, 0x98, 0x98, 0xdd, 0x8f, 0xb7, 0xa4, 0x6b, 0x7a, + 0x9a, 0xd4, 0xb4, 0xe1, 0xab, 0x8d, 0x35, 0x7a, 0x84, 0xe7, 0xf7, 0xd6, 0xe5, 0x1a, 0xa5, 0x8e, + 0x20, 0xef, 0x52, 0xfb, 0xed, 0x22, 0x1c, 0x05, 0x46, 0x7d, 0xdf, 0xda, 0x75, 0x69, 0x27, 0x78, + 0x5d, 0xe3, 0x9e, 0xdc, 0x7f, 0x70, 0xcf, 0xf6, 0x47, 0xbb, 0x67, 0xd5, 0x1c, 0x3b, 0x9f, 0x6a, + 0x8e, 0xe3, 0x29, 0x98, 0x9b, 0x54, 0x48, 0x8f, 0xa9, 0xed, 0x70, 0x4c, 0x3d, 0x49, 0x8f, 0xa9, + 0x42, 0xeb, 0xf3, 0x94, 0xc4, 0x9b, 0x0c, 0x96, 0x9a, 0x65, 0xb5, 0x6f, 0xe0, 0xce, 0x80, 0xbc, + 0x4f, 0x26, 0xd6, 0x8f, 0x44, 0x08, 0x3c, 0x51, 0x06, 0x48, 0x8b, 0x6b, 0x2c, 0x89, 0x5b, 0xfb, + 0xd3, 0x80, 0x62, 0x4c, 0xe1, 0x01, 0xf8, 0x14, 0xf6, 0x1d, 0x35, 0xfb, 0x6c, 0x11, 0x74, 0x56, + 0x11, 0x0a, 0xad, 0xcf, 0x56, 0x1a, 0x7e, 0x73, 0x3c, 0xf6, 0xb7, 0xac, 0x42, 0x48, 0x54, 0x80, + 0x20, 0x8f, 0x50, 0x75, 0xeb, 0x3c, 0x99, 0xb5, 0x79, 0x6e, 0x1a, 0x27, 0xc8, 0x13, 0x12, 0xc3, + 0x3c, 0x8f, 0x21, 0x47, 0xc9, 0x7b, 0xa9, 0x5c, 0xb1, 0xc4, 0xdf, 0xb0, 0xdb, 0xfe, 0x96, 0xa5, + 0x08, 0x9d, 0x02, 0xec, 0x71, 0x72, 0xa5, 0xe7, 0xfa, 0xdf, 0x19, 0xa8, 0xa4, 0xf7, 0x29, 0xe6, + 0x9e, 0x44, 0x5f, 0xc3, 0xe1, 0xba, 0x83, 0xa1, 0xff, 0x1d, 0xb7, 0xd6, 0x9c, 0x0b, 0xf4, 0x25, + 0x94, 0x57, 0x4e, 0xb4, 0xfe, 0xab, 0x94, 0x96, 0x0f, 0x74, 0xa0, 0xf9, 0x94, 0x2c, 0xec, 0x31, + 0x96, 0x38, 0x32, 0xf4, 0x94, 0x2c, 0x4e, 0xb0, 0xc4, 0xe8, 0x31, 0x14, 0x7d, 0x42, 0x78, 0x32, + 0x48, 0x73, 0x1b, 0x07, 0xe9, 0x7e, 0x00, 0xbc, 0x39, 0x47, 0x3f, 0x7d, 0x04, 0x3f, 0x84, 0x83, + 0x29, 0x21, 0xbe, 0xed, 0x5c, 0x62, 0x4a, 0x89, 0x67, 0x33, 0x9f, 0x50, 0xe5, 0xe8, 0xbc, 0x55, + 0x0e, 0x16, 0xba, 0x61, 0xfc, 0xdc, 0x27, 0x14, 0x9d, 0xc1, 0x81, 0xaa, 0x6f, 0xc9, 0xfd, 0xbb, + 0x1f, 0xe3, 0xfe, 0x72, 0xc0, 0xb3, 0x52, 0xe3, 0xf1, 0x45, 0x5a, 0xf5, 0x91, 0xc4, 0x72, 0xae, + 0x2e, 0x26, 0x0e, 0x1b, 0x13, 0xa5, 0x72, 0xd1, 0x52, 0xcf, 0xc8, 0x84, 0xdd, 0x31, 0x91, 0xd8, + 0x55, 0xff, 0xbb, 0x40, 0xce, 0xe8, 0xb5, 0xf6, 0x87, 0x01, 0xa5, 0xa5, 0xc6, 0xf9, 0xc1, 0xc5, + 0x87, 0xcd, 0xa5, 0xfd, 0x2e, 0x38, 0x05, 0x91, 0xa1, 0xf7, 0xd8, 0x5c, 0x9e, 0xaa, 0x00, 0xfa, + 0x02, 0x4a, 0xca, 0xea, 0xb6, 0xc3, 0xa8, 0x98, 0xcf, 0xc8, 0x58, 0xa5, 0x2c, 0x5a, 0x45, 0x15, + 0xed, 0xea, 0x20, 0x6a, 0xc1, 0x0e, 0x57, 0x36, 0xd0, 0xce, 0x3a, 0x5e, 0xf3, 0xe3, 0xd6, 0x46, + 0xb1, 0x34, 0x32, 0xe0, 0x08, 0xb5, 0x09, 0xdd, 0xb2, 0xb5, 0x9c, 0x70, 0x9b, 0x96, 0x46, 0x3e, + 0xfc, 0x01, 0x0e, 0x6e, 0x5c, 0x04, 0x50, 0x0d, 0xfe, 0xd7, 0x6f, 0x0f, 0x4e, 0x46, 0xfd, 0xf6, + 0xcb, 0x9e, 0x3d, 0xb4, 0xce, 0x2f, 0xce, 0xbb, 0xe7, 0xaf, 0xec, 0xd7, 0x83, 0xd1, 0xb0, 0xd7, + 0x3d, 0x3b, 0x3d, 0xeb, 0x9d, 0x54, 0xb6, 0xd0, 0x2e, 0x64, 0x2f, 0x5e, 0x8d, 0x2a, 0x06, 0xca, + 0x43, 0xae, 0xfd, 0xea, 0x62, 0x54, 0xc9, 0x3c, 0xec, 0x41, 0x79, 0xe5, 0x96, 0x86, 0xaa, 0x70, + 0x6f, 0xd0, 0xbb, 0xf8, 0xf9, 0xdc, 0x7a, 0xf9, 0xa1, 0x3c, 0xdd, 0x61, 0xc5, 0x08, 0x1e, 0x5e, + 0x9f, 0x0c, 0x2b, 0x99, 0xd6, 0x9b, 0x54, 0x49, 0x7c, 0x14, 0xde, 0xd9, 0xd0, 0x29, 0x14, 0x4e, + 0x58, 0x1c, 0x46, 0x77, 0xd6, 0xcb, 0x71, 0x75, 0x6c, 0x6e, 0xd0, 0xc9, 0xaf, 0x6d, 0xd5, 0x8d, + 0xaf, 0x8c, 0xce, 0x14, 0x6e, 0xbb, 0x2c, 0xc4, 0x60, 0x4f, 0x8a, 0x86, 0x4b, 0x25, 0xe1, 0x14, + 0x7b, 0x9d, 0x72, 0x02, 0x57, 0xd5, 0x0f, 0x8d, 0x5f, 0x9e, 0x4f, 0x18, 0x9b, 0x78, 0xa4, 0x31, + 0x61, 0x1e, 0xa6, 0x93, 0x06, 0xe3, 0x93, 0xa6, 0xba, 0x0a, 0x3b, 0x9c, 0x28, 0xe3, 0x62, 0x4f, + 0x34, 0x83, 0x24, 0xcd, 0x28, 0x49, 0x53, 0x9d, 0x3a, 0x05, 0xb2, 0x27, 0x8e, 0xff, 0x76, 0x47, + 0xbd, 0x3f, 0xfa, 0x37, 0x00, 0x00, 0xff, 0xff, 0x6e, 0x37, 0x34, 0x9b, 0x67, 0x0b, 0x00, 0x00, } diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp/transport_security_common.pb.go b/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/transport_security_common.pb.go similarity index 71% rename from vendor/google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp/transport_security_common.pb.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/transport_security_common.pb.go index 120700eaaad5b095549aded9b69f1c24c51f5327..27510d4de912022f462c5448f26952b8597852fd 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp/transport_security_common.pb.go +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/transport_security_common.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // source: grpc/gcp/transport_security_common.proto -package grpc_gcp // import "google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp" +package grpc_gcp // import "google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp" import proto "github.com/golang/protobuf/proto" import fmt "fmt" @@ -43,7 +43,7 @@ func (x SecurityLevel) String() string { return proto.EnumName(SecurityLevel_name, int32(x)) } func (SecurityLevel) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_transport_security_common_6489ab913bf26255, []int{0} + return fileDescriptor_transport_security_common_71945991f2c3b4a6, []int{0} } // Max and min supported RPC protocol versions. @@ -61,7 +61,7 @@ func (m *RpcProtocolVersions) Reset() { *m = RpcProtocolVersions{} } func (m *RpcProtocolVersions) String() string { return proto.CompactTextString(m) } func (*RpcProtocolVersions) ProtoMessage() {} func (*RpcProtocolVersions) Descriptor() ([]byte, []int) { - return fileDescriptor_transport_security_common_6489ab913bf26255, []int{0} + return fileDescriptor_transport_security_common_71945991f2c3b4a6, []int{0} } func (m *RpcProtocolVersions) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RpcProtocolVersions.Unmarshal(m, b) @@ -108,7 +108,7 @@ func (m *RpcProtocolVersions_Version) Reset() { *m = RpcProtocolVersions func (m *RpcProtocolVersions_Version) String() string { return proto.CompactTextString(m) } func (*RpcProtocolVersions_Version) ProtoMessage() {} func (*RpcProtocolVersions_Version) Descriptor() ([]byte, []int) { - return fileDescriptor_transport_security_common_6489ab913bf26255, []int{0, 0} + return fileDescriptor_transport_security_common_71945991f2c3b4a6, []int{0, 0} } func (m *RpcProtocolVersions_Version) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RpcProtocolVersions_Version.Unmarshal(m, b) @@ -149,30 +149,30 @@ func init() { } func init() { - proto.RegisterFile("grpc/gcp/transport_security_common.proto", fileDescriptor_transport_security_common_6489ab913bf26255) + proto.RegisterFile("grpc/gcp/transport_security_common.proto", fileDescriptor_transport_security_common_71945991f2c3b4a6) } -var fileDescriptor_transport_security_common_6489ab913bf26255 = []byte{ - // 324 bytes of a gzipped FileDescriptorProto +var fileDescriptor_transport_security_common_71945991f2c3b4a6 = []byte{ + // 323 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x91, 0x41, 0x4b, 0x3b, 0x31, 0x10, 0xc5, 0xff, 0x5b, 0xf8, 0xab, 0x44, 0x56, 0xeb, 0x6a, 0x41, 0xc5, 0x83, 0x08, 0x42, 0xf1, - 0x90, 0x05, 0xc5, 0x93, 0xa7, 0xb6, 0x16, 0x29, 0xd4, 0x6d, 0xdd, 0xd6, 0x42, 0xbd, 0x84, 0x18, - 0x43, 0x88, 0x64, 0x33, 0x61, 0x36, 0x96, 0xfa, 0x95, 0xfd, 0x14, 0xb2, 0x69, 0x97, 0x22, 0x78, - 0xf1, 0x96, 0xf7, 0x98, 0xf9, 0x4d, 0x66, 0x1e, 0x69, 0x2b, 0x74, 0x22, 0x55, 0xc2, 0xa5, 0x1e, - 0xb9, 0x2d, 0x1d, 0xa0, 0x67, 0xa5, 0x14, 0x1f, 0xa8, 0xfd, 0x27, 0x13, 0x50, 0x14, 0x60, 0xa9, - 0x43, 0xf0, 0x90, 0xec, 0x54, 0x95, 0x54, 0x09, 0x77, 0xf1, 0x15, 0x91, 0xc3, 0xdc, 0x89, 0x71, - 0x65, 0x0b, 0x30, 0x33, 0x89, 0xa5, 0x06, 0x5b, 0x26, 0x8f, 0x64, 0xbf, 0xe0, 0x4b, 0x86, 0x4e, - 0xb0, 0xc5, 0xca, 0x3b, 0x8e, 0xce, 0xa3, 0xf6, 0xee, 0xf5, 0x25, 0xad, 0x7b, 0xe9, 0x2f, 0x7d, - 0x74, 0xfd, 0xc8, 0xe3, 0x82, 0x2f, 0x73, 0x27, 0xd6, 0x32, 0xe0, 0xb4, 0xfd, 0x81, 0x6b, 0xfc, - 0x0d, 0xa7, 0xed, 0x06, 0x77, 0x7a, 0x4b, 0xb6, 0x6b, 0xf2, 0x11, 0xf9, 0x5f, 0xf0, 0x77, 0xc0, - 0xf0, 0xbd, 0x38, 0x5f, 0x89, 0xe0, 0x6a, 0x0b, 0x18, 0xa6, 0x54, 0x6e, 0x25, 0xae, 0x9e, 0x48, - 0x3c, 0x59, 0xdf, 0x63, 0x28, 0x17, 0xd2, 0x24, 0x07, 0x24, 0x9e, 0xf4, 0x7b, 0xcf, 0xf9, 0x60, - 0x3a, 0x67, 0xd9, 0x28, 0xeb, 0x37, 0xff, 0x25, 0x09, 0xd9, 0x1b, 0x64, 0xd3, 0xfe, 0x43, 0xf0, - 0x46, 0xd9, 0x70, 0xde, 0x8c, 0x92, 0x13, 0xd2, 0xda, 0x78, 0x9d, 0xec, 0x9e, 0x8d, 0xf3, 0xc1, - 0xac, 0xd3, 0x9b, 0x37, 0x1b, 0x5d, 0x4f, 0x5a, 0x1a, 0x56, 0x3b, 0x70, 0xe3, 0x4b, 0xaa, 0xad, - 0x97, 0x68, 0xb9, 0xe9, 0x9e, 0x4d, 0xeb, 0x0c, 0xea, 0x91, 0xbd, 0x90, 0x40, 0x58, 0x71, 0x1c, - 0xbd, 0xdc, 0x29, 0x00, 0x65, 0x24, 0x55, 0x60, 0xb8, 0x55, 0x14, 0x50, 0xa5, 0x21, 0x3e, 0x81, - 0xf2, 0x4d, 0x5a, 0xaf, 0xb9, 0x29, 0xd3, 0x8a, 0x98, 0x0a, 0x40, 0x99, 0x86, 0xd8, 0x42, 0x01, - 0x53, 0xc2, 0xbd, 0x6e, 0x05, 0x7d, 0xf3, 0x1d, 0x00, 0x00, 0xff, 0xff, 0xa8, 0xc8, 0x38, 0x9d, - 0xf2, 0x01, 0x00, 0x00, + 0x90, 0x05, 0xc5, 0xb3, 0xb4, 0xb5, 0x48, 0xa1, 0x6e, 0xeb, 0xb6, 0x16, 0xea, 0x25, 0xc4, 0x18, + 0x42, 0x24, 0x9b, 0x09, 0xb3, 0xb1, 0xd4, 0xaf, 0xec, 0xa7, 0x90, 0x4d, 0xbb, 0x14, 0xc1, 0x8b, + 0xb7, 0xbc, 0xc7, 0xcc, 0x6f, 0x32, 0xf3, 0x48, 0x5b, 0xa1, 0x13, 0xa9, 0x12, 0x2e, 0xf5, 0xc8, + 0x6d, 0xe9, 0x00, 0x3d, 0x2b, 0xa5, 0xf8, 0x40, 0xed, 0x3f, 0x99, 0x80, 0xa2, 0x00, 0x4b, 0x1d, + 0x82, 0x87, 0x64, 0xa7, 0xaa, 0xa4, 0x4a, 0xb8, 0x8b, 0xaf, 0x88, 0x1c, 0xe6, 0x4e, 0x8c, 0x2b, + 0x5b, 0x80, 0x99, 0x49, 0x2c, 0x35, 0xd8, 0x32, 0x79, 0x24, 0xfb, 0x05, 0x5f, 0x32, 0x74, 0x82, + 0x2d, 0x56, 0xde, 0x71, 0x74, 0x1e, 0xb5, 0x77, 0xaf, 0x2f, 0x69, 0xdd, 0x4b, 0x7f, 0xe9, 0xa3, + 0xeb, 0x47, 0x1e, 0x17, 0x7c, 0x99, 0x3b, 0xb1, 0x96, 0x01, 0xa7, 0xed, 0x0f, 0x5c, 0xe3, 0x6f, + 0x38, 0x6d, 0x37, 0xb8, 0xd3, 0x5b, 0xb2, 0x5d, 0x93, 0x8f, 0xc8, 0xff, 0x82, 0xbf, 0x03, 0x86, + 0xef, 0xc5, 0xf9, 0x4a, 0x04, 0x57, 0x5b, 0xc0, 0x30, 0xa5, 0x72, 0x2b, 0x71, 0xf5, 0x44, 0xe2, + 0xc9, 0xfa, 0x1e, 0x43, 0xb9, 0x90, 0x26, 0x39, 0x20, 0xf1, 0xa4, 0xdf, 0x7b, 0xce, 0x07, 0xd3, + 0x39, 0xcb, 0x46, 0x59, 0xbf, 0xf9, 0x2f, 0x49, 0xc8, 0xde, 0x20, 0x9b, 0xf6, 0x1f, 0x82, 0x37, + 0xca, 0x86, 0xf3, 0x66, 0x94, 0x9c, 0x90, 0xd6, 0xc6, 0xeb, 0x64, 0xf7, 0x6c, 0x9c, 0x0f, 0x66, + 0x9d, 0xde, 0xbc, 0xd9, 0xe8, 0x2e, 0x49, 0x4b, 0xc3, 0x6a, 0x07, 0x6e, 0x7c, 0x49, 0xb5, 0xf5, + 0x12, 0x2d, 0x37, 0xdd, 0xb3, 0x69, 0x9d, 0x41, 0x3d, 0xb2, 0x17, 0x12, 0x08, 0x2b, 0x8e, 0xa3, + 0x97, 0x3b, 0x05, 0xa0, 0x8c, 0xa4, 0x0a, 0x0c, 0xb7, 0x8a, 0x02, 0xaa, 0x34, 0xc4, 0x27, 0x50, + 0xbe, 0x49, 0xeb, 0x35, 0x37, 0x65, 0x5a, 0x11, 0xd3, 0x9a, 0x98, 0x86, 0xe8, 0x42, 0x11, 0x53, + 0xc2, 0xbd, 0x6e, 0x05, 0x7d, 0xf3, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x31, 0x14, 0xb4, 0x11, 0xf6, + 0x01, 0x00, 0x00, } diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/regenerate.sh b/vendor/google.golang.org/grpc/credentials/alts/internal/regenerate.sh similarity index 100% rename from vendor/google.golang.org/grpc/credentials/alts/core/regenerate.sh rename to vendor/google.golang.org/grpc/credentials/alts/internal/regenerate.sh diff --git a/vendor/google.golang.org/grpc/credentials/alts/core/testutil/testutil.go b/vendor/google.golang.org/grpc/credentials/alts/internal/testutil/testutil.go similarity index 98% rename from vendor/google.golang.org/grpc/credentials/alts/core/testutil/testutil.go rename to vendor/google.golang.org/grpc/credentials/alts/internal/testutil/testutil.go index 91cbd03963f933435135b68d30e70fc865f957d6..e114719d5a8816a1dd0c88c76f79e44d279e8982 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/core/testutil/testutil.go +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/testutil/testutil.go @@ -26,7 +26,7 @@ import ( "net" "sync" - "google.golang.org/grpc/credentials/alts/core/conn" + "google.golang.org/grpc/credentials/alts/internal/conn" ) // Stats is used to collect statistics about concurrent handshake calls. diff --git a/vendor/google.golang.org/grpc/credentials/alts/utils.go b/vendor/google.golang.org/grpc/credentials/alts/utils.go index 9f92eb1dd3fec032fac4c384dd4a22aacbab9993..4ed27c605b6b2f8ff3ce802a2d6a139005a8be03 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/utils.go +++ b/vendor/google.golang.org/grpc/credentials/alts/utils.go @@ -19,6 +19,7 @@ package alts import ( + "context" "errors" "fmt" "io" @@ -29,9 +30,7 @@ import ( "regexp" "runtime" "strings" - "time" - "golang.org/x/net/context" "google.golang.org/grpc/peer" ) @@ -41,7 +40,6 @@ const ( windowsCheckCommandArgs = "Get-WmiObject -Class Win32_BIOS" powershellOutputFilter = "Manufacturer" windowsManufacturerRegex = ":(.*)" - windowsCheckTimeout = 30 * time.Second ) type platformError string @@ -124,13 +122,20 @@ func readManufacturer() ([]byte, error) { // information about the communicating peer. For client-side, use grpc.Peer() // CallOption. func AuthInfoFromContext(ctx context.Context) (AuthInfo, error) { - peer, ok := peer.FromContext(ctx) + p, ok := peer.FromContext(ctx) if !ok { return nil, errors.New("no Peer found in Context") } - altsAuthInfo, ok := peer.AuthInfo.(AuthInfo) + return AuthInfoFromPeer(p) +} + +// AuthInfoFromPeer extracts the alts.AuthInfo object from the given peer, if it +// exists. This API should be used by gRPC clients after obtaining a peer object +// using the grpc.Peer() CallOption. +func AuthInfoFromPeer(p *peer.Peer) (AuthInfo, error) { + altsAuthInfo, ok := p.AuthInfo.(AuthInfo) if !ok { - return nil, errors.New("no alts.AuthInfo found in Context") + return nil, errors.New("no alts.AuthInfo found in Peer") } return altsAuthInfo, nil } diff --git a/vendor/google.golang.org/grpc/credentials/alts/utils_test.go b/vendor/google.golang.org/grpc/credentials/alts/utils_test.go index 4724103f6cea33b3b5903cbf2a554a020c94318a..3c7e43db14a0a00bd7ed94243c48f3c3afd28500 100644 --- a/vendor/google.golang.org/grpc/credentials/alts/utils_test.go +++ b/vendor/google.golang.org/grpc/credentials/alts/utils_test.go @@ -19,12 +19,12 @@ package alts import ( + "context" "io" "strings" "testing" - "golang.org/x/net/context" - altspb "google.golang.org/grpc/credentials/alts/core/proto/grpc_gcp" + altspb "google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp" "google.golang.org/grpc/peer" ) @@ -98,6 +98,34 @@ func TestAuthInfoFromContext(t *testing.T) { } } +func TestAuthInfoFromPeer(t *testing.T) { + altsAuthInfo := &fakeALTSAuthInfo{} + p := &peer.Peer{ + AuthInfo: altsAuthInfo, + } + for _, tc := range []struct { + desc string + p *peer.Peer + success bool + out AuthInfo + }{ + { + "working case", + p, + true, + altsAuthInfo, + }, + } { + authInfo, err := AuthInfoFromPeer(tc.p) + if got, want := (err == nil), tc.success; got != want { + t.Errorf("%v: AuthInfoFromPeer(_)=(err=nil)=%v, want %v", tc.desc, got, want) + } + if got, want := authInfo, tc.out; got != want { + t.Errorf("%v:, AuthInfoFromPeer(_)=(%v, _), want (%v, _)", tc.desc, got, want) + } + } +} + type fakeALTSAuthInfo struct{} func (*fakeALTSAuthInfo) AuthType() string { return "" } diff --git a/vendor/google.golang.org/grpc/credentials/credentials.go b/vendor/google.golang.org/grpc/credentials/credentials.go index 3351bf0ee5f8752949b018dca9e201c59c08b2eb..a851560456b4261a30512990426ff9df46587914 100644 --- a/vendor/google.golang.org/grpc/credentials/credentials.go +++ b/vendor/google.golang.org/grpc/credentials/credentials.go @@ -23,6 +23,7 @@ package credentials // import "google.golang.org/grpc/credentials" import ( + "context" "crypto/tls" "crypto/x509" "errors" @@ -31,7 +32,8 @@ import ( "net" "strings" - "golang.org/x/net/context" + "github.com/golang/protobuf/proto" + "google.golang.org/grpc/credentials/internal" ) // alpnProtoStr are the specified application level protocols for gRPC. @@ -107,6 +109,25 @@ type TransportCredentials interface { OverrideServerName(string) error } +// Bundle is a combination of TransportCredentials and PerRPCCredentials. +// +// It also contains a mode switching method, so it can be used as a combination +// of different credential policies. +// +// Bundle cannot be used together with individual TransportCredentials. +// PerRPCCredentials from Bundle will be appended to other PerRPCCredentials. +// +// This API is experimental. +type Bundle interface { + TransportCredentials() TransportCredentials + PerRPCCredentials() PerRPCCredentials + // NewWithMode should make a copy of Bundle, and switch mode. Modifying the + // existing Bundle may cause races. + // + // NewWithMode returns nil if the requested mode is not supported. + NewWithMode(mode string) (Bundle, error) +} + // TLSInfo contains the auth information for a TLS authenticated connection. // It implements the AuthInfo interface. type TLSInfo struct { @@ -118,6 +139,18 @@ func (t TLSInfo) AuthType() string { return "tls" } +// GetSecurityValue returns security info requested by channelz. +func (t TLSInfo) GetSecurityValue() ChannelzSecurityValue { + v := &TLSChannelzSecurityValue{ + StandardName: cipherSuiteLookup[t.State.CipherSuite], + } + // Currently there's no way to get LocalCertificate info from tls package. + if len(t.State.PeerCertificates) > 0 { + v.RemoteCertificate = t.State.PeerCertificates[0].Raw + } + return v +} + // tlsCreds is the credentials required for authenticating a connection using TLS. type tlsCreds struct { // TLS configuration @@ -155,7 +188,7 @@ func (c *tlsCreds) ClientHandshake(ctx context.Context, authority string, rawCon case <-ctx.Done(): return nil, nil, ctx.Err() } - return conn, TLSInfo{conn.ConnectionState()}, nil + return internal.WrapSyscallConn(rawConn, conn), TLSInfo{conn.ConnectionState()}, nil } func (c *tlsCreds) ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error) { @@ -163,7 +196,7 @@ func (c *tlsCreds) ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error) if err := conn.Handshake(); err != nil { return nil, nil, err } - return conn, TLSInfo{conn.ConnectionState()}, nil + return internal.WrapSyscallConn(rawConn, conn), TLSInfo{conn.ConnectionState()}, nil } func (c *tlsCreds) Clone() TransportCredentials { @@ -218,3 +251,78 @@ func NewServerTLSFromFile(certFile, keyFile string) (TransportCredentials, error } return NewTLS(&tls.Config{Certificates: []tls.Certificate{cert}}), nil } + +// ChannelzSecurityInfo defines the interface that security protocols should implement +// in order to provide security info to channelz. +type ChannelzSecurityInfo interface { + GetSecurityValue() ChannelzSecurityValue +} + +// ChannelzSecurityValue defines the interface that GetSecurityValue() return value +// should satisfy. This interface should only be satisfied by *TLSChannelzSecurityValue +// and *OtherChannelzSecurityValue. +type ChannelzSecurityValue interface { + isChannelzSecurityValue() +} + +// TLSChannelzSecurityValue defines the struct that TLS protocol should return +// from GetSecurityValue(), containing security info like cipher and certificate used. +type TLSChannelzSecurityValue struct { + StandardName string + LocalCertificate []byte + RemoteCertificate []byte +} + +func (*TLSChannelzSecurityValue) isChannelzSecurityValue() {} + +// OtherChannelzSecurityValue defines the struct that non-TLS protocol should return +// from GetSecurityValue(), which contains protocol specific security info. Note +// the Value field will be sent to users of channelz requesting channel info, and +// thus sensitive info should better be avoided. +type OtherChannelzSecurityValue struct { + Name string + Value proto.Message +} + +func (*OtherChannelzSecurityValue) isChannelzSecurityValue() {} + +var cipherSuiteLookup = map[uint16]string{ + tls.TLS_RSA_WITH_RC4_128_SHA: "TLS_RSA_WITH_RC4_128_SHA", + tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_RSA_WITH_3DES_EDE_CBC_SHA", + tls.TLS_RSA_WITH_AES_128_CBC_SHA: "TLS_RSA_WITH_AES_128_CBC_SHA", + tls.TLS_RSA_WITH_AES_256_CBC_SHA: "TLS_RSA_WITH_AES_256_CBC_SHA", + tls.TLS_RSA_WITH_AES_128_GCM_SHA256: "TLS_RSA_WITH_AES_128_GCM_SHA256", + tls.TLS_RSA_WITH_AES_256_GCM_SHA384: "TLS_RSA_WITH_AES_256_GCM_SHA384", + tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA: "TLS_ECDHE_RSA_WITH_RC4_128_SHA", + tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + tls.TLS_FALLBACK_SCSV: "TLS_FALLBACK_SCSV", + tls.TLS_RSA_WITH_AES_128_CBC_SHA256: "TLS_RSA_WITH_AES_128_CBC_SHA256", + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", +} + +// cloneTLSConfig returns a shallow clone of the exported +// fields of cfg, ignoring the unexported sync.Once, which +// contains a mutex and must not be copied. +// +// If cfg is nil, a new zero tls.Config is returned. +// +// TODO: inline this function if possible. +func cloneTLSConfig(cfg *tls.Config) *tls.Config { + if cfg == nil { + return &tls.Config{} + } + + return cfg.Clone() +} diff --git a/vendor/google.golang.org/grpc/credentials/credentials_test.go b/vendor/google.golang.org/grpc/credentials/credentials_test.go index 9b13db51d438ccd280df3ae3655e65dce005b1bb..cb091de08092261de2461a4fbf757b813c230aaf 100644 --- a/vendor/google.golang.org/grpc/credentials/credentials_test.go +++ b/vendor/google.golang.org/grpc/credentials/credentials_test.go @@ -19,11 +19,11 @@ package credentials import ( + "context" "crypto/tls" "net" "testing" - "golang.org/x/net/context" "google.golang.org/grpc/testdata" ) diff --git a/vendor/google.golang.org/grpc/credentials/credentials_util_go17.go b/vendor/google.golang.org/grpc/credentials/credentials_util_go17.go deleted file mode 100644 index 60409aac0fbc6b52145183fee31473d95ac54571..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/credentials/credentials_util_go17.go +++ /dev/null @@ -1,60 +0,0 @@ -// +build go1.7 -// +build !go1.8 - -/* - * - * Copyright 2016 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package credentials - -import ( - "crypto/tls" -) - -// cloneTLSConfig returns a shallow clone of the exported -// fields of cfg, ignoring the unexported sync.Once, which -// contains a mutex and must not be copied. -// -// If cfg is nil, a new zero tls.Config is returned. -func cloneTLSConfig(cfg *tls.Config) *tls.Config { - if cfg == nil { - return &tls.Config{} - } - return &tls.Config{ - Rand: cfg.Rand, - Time: cfg.Time, - Certificates: cfg.Certificates, - NameToCertificate: cfg.NameToCertificate, - GetCertificate: cfg.GetCertificate, - RootCAs: cfg.RootCAs, - NextProtos: cfg.NextProtos, - ServerName: cfg.ServerName, - ClientAuth: cfg.ClientAuth, - ClientCAs: cfg.ClientCAs, - InsecureSkipVerify: cfg.InsecureSkipVerify, - CipherSuites: cfg.CipherSuites, - PreferServerCipherSuites: cfg.PreferServerCipherSuites, - SessionTicketsDisabled: cfg.SessionTicketsDisabled, - SessionTicketKey: cfg.SessionTicketKey, - ClientSessionCache: cfg.ClientSessionCache, - MinVersion: cfg.MinVersion, - MaxVersion: cfg.MaxVersion, - CurvePreferences: cfg.CurvePreferences, - DynamicRecordSizingDisabled: cfg.DynamicRecordSizingDisabled, - Renegotiation: cfg.Renegotiation, - } -} diff --git a/vendor/google.golang.org/grpc/credentials/credentials_util_pre_go17.go b/vendor/google.golang.org/grpc/credentials/credentials_util_pre_go17.go deleted file mode 100644 index d6bbcc9fdd95dfe77fa9cd36e5437d19694890e9..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/credentials/credentials_util_pre_go17.go +++ /dev/null @@ -1,57 +0,0 @@ -// +build !go1.7 - -/* - * - * Copyright 2016 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package credentials - -import ( - "crypto/tls" -) - -// cloneTLSConfig returns a shallow clone of the exported -// fields of cfg, ignoring the unexported sync.Once, which -// contains a mutex and must not be copied. -// -// If cfg is nil, a new zero tls.Config is returned. -func cloneTLSConfig(cfg *tls.Config) *tls.Config { - if cfg == nil { - return &tls.Config{} - } - return &tls.Config{ - Rand: cfg.Rand, - Time: cfg.Time, - Certificates: cfg.Certificates, - NameToCertificate: cfg.NameToCertificate, - GetCertificate: cfg.GetCertificate, - RootCAs: cfg.RootCAs, - NextProtos: cfg.NextProtos, - ServerName: cfg.ServerName, - ClientAuth: cfg.ClientAuth, - ClientCAs: cfg.ClientCAs, - InsecureSkipVerify: cfg.InsecureSkipVerify, - CipherSuites: cfg.CipherSuites, - PreferServerCipherSuites: cfg.PreferServerCipherSuites, - SessionTicketsDisabled: cfg.SessionTicketsDisabled, - SessionTicketKey: cfg.SessionTicketKey, - ClientSessionCache: cfg.ClientSessionCache, - MinVersion: cfg.MinVersion, - MaxVersion: cfg.MaxVersion, - CurvePreferences: cfg.CurvePreferences, - } -} diff --git a/vendor/google.golang.org/grpc/credentials/google/google.go b/vendor/google.golang.org/grpc/credentials/google/google.go new file mode 100644 index 0000000000000000000000000000000000000000..23079c80a6708338fd8e7552287d9efa2f39b5ed --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/google/google.go @@ -0,0 +1,101 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package google defines credentials for google cloud services. +package google + +import ( + "context" + "fmt" + "time" + + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/alts" + "google.golang.org/grpc/credentials/oauth" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/internal" +) + +const tokenRequestTimeout = 30 * time.Second + +// NewDefaultCredentials returns a credentials bundle that is configured to work +// with google services. +// +// This API is experimental. +func NewDefaultCredentials() credentials.Bundle { + c := &creds{} + bundle, err := c.NewWithMode(internal.CredsBundleModeFallback) + if err != nil { + grpclog.Warningf("google default creds: failed to create new creds: %v", err) + } + return bundle +} + +// creds implements credentials.Bundle. +type creds struct { + // Supported modes are defined in internal/internal.go. + mode string + // The transport credentials associated with this bundle. + transportCreds credentials.TransportCredentials + // The per RPC credentials associated with this bundle. + perRPCCreds credentials.PerRPCCredentials +} + +func (c *creds) TransportCredentials() credentials.TransportCredentials { + return c.transportCreds +} + +func (c *creds) PerRPCCredentials() credentials.PerRPCCredentials { + if c == nil { + return nil + } + return c.perRPCCreds +} + +// NewWithMode should make a copy of Bundle, and switch mode. Modifying the +// existing Bundle may cause races. +func (c *creds) NewWithMode(mode string) (credentials.Bundle, error) { + newCreds := &creds{mode: mode} + + // Create transport credentials. + switch mode { + case internal.CredsBundleModeFallback: + newCreds.transportCreds = credentials.NewTLS(nil) + case internal.CredsBundleModeBackendFromBalancer, internal.CredsBundleModeBalancer: + // Only the clients can use google default credentials, so we only need + // to create new ALTS client creds here. + newCreds.transportCreds = alts.NewClientCreds(alts.DefaultClientOptions()) + default: + return nil, fmt.Errorf("google default creds: unsupported mode: %v", mode) + } + + if mode == internal.CredsBundleModeFallback || mode == internal.CredsBundleModeBackendFromBalancer { + // Create per RPC credentials. + // For the time being, we required per RPC credentials for both TLS and + // ALTS. In the future, this will only be required for TLS. + ctx, cancel := context.WithTimeout(context.Background(), tokenRequestTimeout) + defer cancel() + var err error + newCreds.perRPCCreds, err = oauth.NewApplicationDefault(ctx) + if err != nil { + grpclog.Warningf("google default creds: failed to create application oauth: %v", err) + } + } + + return newCreds, nil +} diff --git a/vendor/google.golang.org/grpc/credentials/internal/syscallconn.go b/vendor/google.golang.org/grpc/credentials/internal/syscallconn.go new file mode 100644 index 0000000000000000000000000000000000000000..2f4472becc7c97a95f1a8160693d95c367b9e91c --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/internal/syscallconn.go @@ -0,0 +1,61 @@ +// +build !appengine + +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package internal contains credentials-internal code. +package internal + +import ( + "net" + "syscall" +) + +type sysConn = syscall.Conn + +// syscallConn keeps reference of rawConn to support syscall.Conn for channelz. +// SyscallConn() (the method in interface syscall.Conn) is explicitly +// implemented on this type, +// +// Interface syscall.Conn is implemented by most net.Conn implementations (e.g. +// TCPConn, UnixConn), but is not part of net.Conn interface. So wrapper conns +// that embed net.Conn don't implement syscall.Conn. (Side note: tls.Conn +// doesn't embed net.Conn, so even if syscall.Conn is part of net.Conn, it won't +// help here). +type syscallConn struct { + net.Conn + // sysConn is a type alias of syscall.Conn. It's necessary because the name + // `Conn` collides with `net.Conn`. + sysConn +} + +// WrapSyscallConn tries to wrap rawConn and newConn into a net.Conn that +// implements syscall.Conn. rawConn will be used to support syscall, and newConn +// will be used for read/write. +// +// This function returns newConn if rawConn doesn't implement syscall.Conn. +func WrapSyscallConn(rawConn, newConn net.Conn) net.Conn { + sysConn, ok := rawConn.(syscall.Conn) + if !ok { + return newConn + } + return &syscallConn{ + Conn: newConn, + sysConn: sysConn, + } +} diff --git a/vendor/google.golang.org/grpc/resolver/dns/go18.go b/vendor/google.golang.org/grpc/credentials/internal/syscallconn_appengine.go similarity index 73% rename from vendor/google.golang.org/grpc/resolver/dns/go18.go rename to vendor/google.golang.org/grpc/credentials/internal/syscallconn_appengine.go index fa34f14cad48fea67e8434c0850cece172edcaae..d4346e9eabe6f2a8c468ace52f0b0d1517ce269f 100644 --- a/vendor/google.golang.org/grpc/resolver/dns/go18.go +++ b/vendor/google.golang.org/grpc/credentials/internal/syscallconn_appengine.go @@ -1,8 +1,8 @@ -// +build go1.8 +// +build appengine /* * - * Copyright 2017 gRPC authors. + * Copyright 2018 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,12 +18,13 @@ * */ -package dns +package internal -import "net" - -var ( - lookupHost = net.DefaultResolver.LookupHost - lookupSRV = net.DefaultResolver.LookupSRV - lookupTXT = net.DefaultResolver.LookupTXT +import ( + "net" ) + +// WrapSyscallConn returns newConn on appengine. +func WrapSyscallConn(rawConn, newConn net.Conn) net.Conn { + return newConn +} diff --git a/vendor/google.golang.org/grpc/credentials/internal/syscallconn_test.go b/vendor/google.golang.org/grpc/credentials/internal/syscallconn_test.go new file mode 100644 index 0000000000000000000000000000000000000000..74567132823867e6e7e57c38bd720d157e8fe8ce --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/internal/syscallconn_test.go @@ -0,0 +1,64 @@ +// +build !appengine + +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package internal_test + +import ( + "net" + "syscall" + "testing" + + "google.golang.org/grpc/credentials/internal" +) + +type syscallConn struct { + net.Conn +} + +func (*syscallConn) SyscallConn() (syscall.RawConn, error) { + return nil, nil +} + +type nonSyscallConn struct { + net.Conn +} + +func TestWrapSyscallConn(t *testing.T) { + sc := &syscallConn{} + nsc := &nonSyscallConn{} + + wrapConn := internal.WrapSyscallConn(sc, nsc) + if _, ok := wrapConn.(syscall.Conn); !ok { + t.Errorf("returned conn (type %T) doesn't implement syscall.Conn, want implement", wrapConn) + } +} + +func TestWrapSyscallConnNoWrap(t *testing.T) { + nscRaw := &nonSyscallConn{} + nsc := &nonSyscallConn{} + + wrapConn := internal.WrapSyscallConn(nscRaw, nsc) + if _, ok := wrapConn.(syscall.Conn); ok { + t.Errorf("returned conn (type %T) implements syscall.Conn, want not implement", wrapConn) + } + if wrapConn != nsc { + t.Errorf("returned conn is %p, want %p (the passed-in newConn)", wrapConn, nsc) + } +} diff --git a/vendor/google.golang.org/grpc/credentials/oauth/oauth.go b/vendor/google.golang.org/grpc/credentials/oauth/oauth.go index f6d597a14fe60e53dcff419270921bd3bfc0cd17..e0e74d8153c6d961bfc816d7a3150597ccb27d9c 100644 --- a/vendor/google.golang.org/grpc/credentials/oauth/oauth.go +++ b/vendor/google.golang.org/grpc/credentials/oauth/oauth.go @@ -20,11 +20,11 @@ package oauth import ( + "context" "fmt" "io/ioutil" "sync" - "golang.org/x/net/context" "golang.org/x/oauth2" "golang.org/x/oauth2/google" "golang.org/x/oauth2/jwt" diff --git a/vendor/google.golang.org/grpc/dialoptions.go b/vendor/google.golang.org/grpc/dialoptions.go new file mode 100644 index 0000000000000000000000000000000000000000..fe00a254d065b44cff440acb401569bb5105101a --- /dev/null +++ b/vendor/google.golang.org/grpc/dialoptions.go @@ -0,0 +1,480 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package grpc + +import ( + "context" + "fmt" + "net" + "time" + + "google.golang.org/grpc/balancer" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/internal" + "google.golang.org/grpc/internal/backoff" + "google.golang.org/grpc/internal/envconfig" + "google.golang.org/grpc/internal/transport" + "google.golang.org/grpc/keepalive" + "google.golang.org/grpc/resolver" + "google.golang.org/grpc/stats" +) + +// dialOptions configure a Dial call. dialOptions are set by the DialOption +// values passed to Dial. +type dialOptions struct { + unaryInt UnaryClientInterceptor + streamInt StreamClientInterceptor + cp Compressor + dc Decompressor + bs backoff.Strategy + block bool + insecure bool + timeout time.Duration + scChan <-chan ServiceConfig + authority string + copts transport.ConnectOptions + callOptions []CallOption + // This is used by v1 balancer dial option WithBalancer to support v1 + // balancer, and also by WithBalancerName dial option. + balancerBuilder balancer.Builder + // This is to support grpclb. + resolverBuilder resolver.Builder + reqHandshake envconfig.RequireHandshakeSetting + channelzParentID int64 + disableServiceConfig bool + disableRetry bool + disableHealthCheck bool +} + +// DialOption configures how we set up the connection. +type DialOption interface { + apply(*dialOptions) +} + +// EmptyDialOption does not alter the dial configuration. It can be embedded in +// another structure to build custom dial options. +// +// This API is EXPERIMENTAL. +type EmptyDialOption struct{} + +func (EmptyDialOption) apply(*dialOptions) {} + +// funcDialOption wraps a function that modifies dialOptions into an +// implementation of the DialOption interface. +type funcDialOption struct { + f func(*dialOptions) +} + +func (fdo *funcDialOption) apply(do *dialOptions) { + fdo.f(do) +} + +func newFuncDialOption(f func(*dialOptions)) *funcDialOption { + return &funcDialOption{ + f: f, + } +} + +// WithWaitForHandshake blocks until the initial settings frame is received from +// the server before assigning RPCs to the connection. +// +// Deprecated: this will become the default behavior in the 1.17 release, and +// will be removed after the 1.18 release. To override the default behavior in +// the 1.17 release, either use this dial option or set the environment +// variable GRPC_GO_READY_BEFORE_HANDSHAKE=on. +func WithWaitForHandshake() DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.reqHandshake = envconfig.RequireHandshakeOn + }) +} + +// WithWriteBufferSize determines how much data can be batched before doing a +// write on the wire. The corresponding memory allocation for this buffer will +// be twice the size to keep syscalls low. The default value for this buffer is +// 32KB. +// +// Zero will disable the write buffer such that each write will be on underlying +// connection. Note: A Send call may not directly translate to a write. +func WithWriteBufferSize(s int) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.copts.WriteBufferSize = s + }) +} + +// WithReadBufferSize lets you set the size of read buffer, this determines how +// much data can be read at most for each read syscall. +// +// The default value for this buffer is 32KB. Zero will disable read buffer for +// a connection so data framer can access the underlying conn directly. +func WithReadBufferSize(s int) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.copts.ReadBufferSize = s + }) +} + +// WithInitialWindowSize returns a DialOption which sets the value for initial +// window size on a stream. The lower bound for window size is 64K and any value +// smaller than that will be ignored. +func WithInitialWindowSize(s int32) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.copts.InitialWindowSize = s + }) +} + +// WithInitialConnWindowSize returns a DialOption which sets the value for +// initial window size on a connection. The lower bound for window size is 64K +// and any value smaller than that will be ignored. +func WithInitialConnWindowSize(s int32) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.copts.InitialConnWindowSize = s + }) +} + +// WithMaxMsgSize returns a DialOption which sets the maximum message size the +// client can receive. +// +// Deprecated: use WithDefaultCallOptions(MaxCallRecvMsgSize(s)) instead. +func WithMaxMsgSize(s int) DialOption { + return WithDefaultCallOptions(MaxCallRecvMsgSize(s)) +} + +// WithDefaultCallOptions returns a DialOption which sets the default +// CallOptions for calls over the connection. +func WithDefaultCallOptions(cos ...CallOption) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.callOptions = append(o.callOptions, cos...) + }) +} + +// WithCodec returns a DialOption which sets a codec for message marshaling and +// unmarshaling. +// +// Deprecated: use WithDefaultCallOptions(CallCustomCodec(c)) instead. +func WithCodec(c Codec) DialOption { + return WithDefaultCallOptions(CallCustomCodec(c)) +} + +// WithCompressor returns a DialOption which sets a Compressor to use for +// message compression. It has lower priority than the compressor set by the +// UseCompressor CallOption. +// +// Deprecated: use UseCompressor instead. +func WithCompressor(cp Compressor) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.cp = cp + }) +} + +// WithDecompressor returns a DialOption which sets a Decompressor to use for +// incoming message decompression. If incoming response messages are encoded +// using the decompressor's Type(), it will be used. Otherwise, the message +// encoding will be used to look up the compressor registered via +// encoding.RegisterCompressor, which will then be used to decompress the +// message. If no compressor is registered for the encoding, an Unimplemented +// status error will be returned. +// +// Deprecated: use encoding.RegisterCompressor instead. +func WithDecompressor(dc Decompressor) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.dc = dc + }) +} + +// WithBalancer returns a DialOption which sets a load balancer with the v1 API. +// Name resolver will be ignored if this DialOption is specified. +// +// Deprecated: use the new balancer APIs in balancer package and +// WithBalancerName. +func WithBalancer(b Balancer) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.balancerBuilder = &balancerWrapperBuilder{ + b: b, + } + }) +} + +// WithBalancerName sets the balancer that the ClientConn will be initialized +// with. Balancer registered with balancerName will be used. This function +// panics if no balancer was registered by balancerName. +// +// The balancer cannot be overridden by balancer option specified by service +// config. +// +// This is an EXPERIMENTAL API. +func WithBalancerName(balancerName string) DialOption { + builder := balancer.Get(balancerName) + if builder == nil { + panic(fmt.Sprintf("grpc.WithBalancerName: no balancer is registered for name %v", balancerName)) + } + return newFuncDialOption(func(o *dialOptions) { + o.balancerBuilder = builder + }) +} + +// withResolverBuilder is only for grpclb. +func withResolverBuilder(b resolver.Builder) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.resolverBuilder = b + }) +} + +// WithServiceConfig returns a DialOption which has a channel to read the +// service configuration. +// +// Deprecated: service config should be received through name resolver, as +// specified here. +// https://github.com/grpc/grpc/blob/master/doc/service_config.md +func WithServiceConfig(c <-chan ServiceConfig) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.scChan = c + }) +} + +// WithBackoffMaxDelay configures the dialer to use the provided maximum delay +// when backing off after failed connection attempts. +func WithBackoffMaxDelay(md time.Duration) DialOption { + return WithBackoffConfig(BackoffConfig{MaxDelay: md}) +} + +// WithBackoffConfig configures the dialer to use the provided backoff +// parameters after connection failures. +// +// Use WithBackoffMaxDelay until more parameters on BackoffConfig are opened up +// for use. +func WithBackoffConfig(b BackoffConfig) DialOption { + return withBackoff(backoff.Exponential{ + MaxDelay: b.MaxDelay, + }) +} + +// withBackoff sets the backoff strategy used for connectRetryNum after a failed +// connection attempt. +// +// This can be exported if arbitrary backoff strategies are allowed by gRPC. +func withBackoff(bs backoff.Strategy) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.bs = bs + }) +} + +// WithBlock returns a DialOption which makes caller of Dial blocks until the +// underlying connection is up. Without this, Dial returns immediately and +// connecting the server happens in background. +func WithBlock() DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.block = true + }) +} + +// WithInsecure returns a DialOption which disables transport security for this +// ClientConn. Note that transport security is required unless WithInsecure is +// set. +func WithInsecure() DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.insecure = true + }) +} + +// WithTransportCredentials returns a DialOption which configures a connection +// level security credentials (e.g., TLS/SSL). This should not be used together +// with WithCredentialsBundle. +func WithTransportCredentials(creds credentials.TransportCredentials) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.copts.TransportCredentials = creds + }) +} + +// WithPerRPCCredentials returns a DialOption which sets credentials and places +// auth state on each outbound RPC. +func WithPerRPCCredentials(creds credentials.PerRPCCredentials) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.copts.PerRPCCredentials = append(o.copts.PerRPCCredentials, creds) + }) +} + +// WithCredentialsBundle returns a DialOption to set a credentials bundle for +// the ClientConn.WithCreds. This should not be used together with +// WithTransportCredentials. +// +// This API is experimental. +func WithCredentialsBundle(b credentials.Bundle) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.copts.CredsBundle = b + }) +} + +// WithTimeout returns a DialOption that configures a timeout for dialing a +// ClientConn initially. This is valid if and only if WithBlock() is present. +// +// Deprecated: use DialContext and context.WithTimeout instead. +func WithTimeout(d time.Duration) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.timeout = d + }) +} + +func withContextDialer(f func(context.Context, string) (net.Conn, error)) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.copts.Dialer = f + }) +} + +func init() { + internal.WithContextDialer = withContextDialer + internal.WithResolverBuilder = withResolverBuilder +} + +// WithDialer returns a DialOption that specifies a function to use for dialing +// network addresses. If FailOnNonTempDialError() is set to true, and an error +// is returned by f, gRPC checks the error's Temporary() method to decide if it +// should try to reconnect to the network address. +func WithDialer(f func(string, time.Duration) (net.Conn, error)) DialOption { + return withContextDialer( + func(ctx context.Context, addr string) (net.Conn, error) { + if deadline, ok := ctx.Deadline(); ok { + return f(addr, deadline.Sub(time.Now())) + } + return f(addr, 0) + }) +} + +// WithStatsHandler returns a DialOption that specifies the stats handler for +// all the RPCs and underlying network connections in this ClientConn. +func WithStatsHandler(h stats.Handler) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.copts.StatsHandler = h + }) +} + +// FailOnNonTempDialError returns a DialOption that specifies if gRPC fails on +// non-temporary dial errors. If f is true, and dialer returns a non-temporary +// error, gRPC will fail the connection to the network address and won't try to +// reconnect. The default value of FailOnNonTempDialError is false. +// +// FailOnNonTempDialError only affects the initial dial, and does not do +// anything useful unless you are also using WithBlock(). +// +// This is an EXPERIMENTAL API. +func FailOnNonTempDialError(f bool) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.copts.FailOnNonTempDialError = f + }) +} + +// WithUserAgent returns a DialOption that specifies a user agent string for all +// the RPCs. +func WithUserAgent(s string) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.copts.UserAgent = s + }) +} + +// WithKeepaliveParams returns a DialOption that specifies keepalive parameters +// for the client transport. +func WithKeepaliveParams(kp keepalive.ClientParameters) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.copts.KeepaliveParams = kp + }) +} + +// WithUnaryInterceptor returns a DialOption that specifies the interceptor for +// unary RPCs. +func WithUnaryInterceptor(f UnaryClientInterceptor) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.unaryInt = f + }) +} + +// WithStreamInterceptor returns a DialOption that specifies the interceptor for +// streaming RPCs. +func WithStreamInterceptor(f StreamClientInterceptor) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.streamInt = f + }) +} + +// WithAuthority returns a DialOption that specifies the value to be used as the +// :authority pseudo-header. This value only works with WithInsecure and has no +// effect if TransportCredentials are present. +func WithAuthority(a string) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.authority = a + }) +} + +// WithChannelzParentID returns a DialOption that specifies the channelz ID of +// current ClientConn's parent. This function is used in nested channel creation +// (e.g. grpclb dial). +func WithChannelzParentID(id int64) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.channelzParentID = id + }) +} + +// WithDisableServiceConfig returns a DialOption that causes grpc to ignore any +// service config provided by the resolver and provides a hint to the resolver +// to not fetch service configs. +func WithDisableServiceConfig() DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.disableServiceConfig = true + }) +} + +// WithDisableRetry returns a DialOption that disables retries, even if the +// service config enables them. This does not impact transparent retries, which +// will happen automatically if no data is written to the wire or if the RPC is +// unprocessed by the remote server. +// +// Retry support is currently disabled by default, but will be enabled by +// default in the future. Until then, it may be enabled by setting the +// environment variable "GRPC_GO_RETRY" to "on". +// +// This API is EXPERIMENTAL. +func WithDisableRetry() DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.disableRetry = true + }) +} + +// WithMaxHeaderListSize returns a DialOption that specifies the maximum +// (uncompressed) size of header list that the client is prepared to accept. +func WithMaxHeaderListSize(s uint32) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.copts.MaxHeaderListSize = &s + }) +} + +// WithDisableHealthCheck disables the LB channel health checking for all SubConns of this ClientConn. +// +// This API is EXPERIMENTAL. +func WithDisableHealthCheck() DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.disableHealthCheck = true + }) +} +func defaultDialOptions() dialOptions { + return dialOptions{ + disableRetry: !envconfig.Retry, + reqHandshake: envconfig.RequireHandshake, + copts: transport.ConnectOptions{ + WriteBufferSize: defaultWriteBufSize, + ReadBufferSize: defaultReadBufSize, + }, + } +} diff --git a/vendor/google.golang.org/grpc/encoding/proto/proto_benchmark_test.go b/vendor/google.golang.org/grpc/encoding/proto/proto_benchmark_test.go index 63ea57de2edbd7b78e3cfe5b508d137261cf3812..7d4819859fdead4185d9fbb4985d1cce9cb36fd1 100644 --- a/vendor/google.golang.org/grpc/encoding/proto/proto_benchmark_test.go +++ b/vendor/google.golang.org/grpc/encoding/proto/proto_benchmark_test.go @@ -1,5 +1,3 @@ -// +build go1.7 - /* * * Copyright 2014 gRPC authors. diff --git a/vendor/google.golang.org/grpc/examples/helloworld/greeter_client/main.go b/vendor/google.golang.org/grpc/examples/helloworld/greeter_client/main.go index 4b99ff5a7066079be55e9517ba2dea05a49d4b9b..8c44ef03ad881e4b00b2725ae8570326efd7ce6a 100644 --- a/vendor/google.golang.org/grpc/examples/helloworld/greeter_client/main.go +++ b/vendor/google.golang.org/grpc/examples/helloworld/greeter_client/main.go @@ -19,11 +19,11 @@ package main import ( + "context" "log" "os" "time" - "golang.org/x/net/context" "google.golang.org/grpc" pb "google.golang.org/grpc/examples/helloworld/helloworld" ) diff --git a/vendor/google.golang.org/grpc/examples/helloworld/greeter_server/main.go b/vendor/google.golang.org/grpc/examples/helloworld/greeter_server/main.go index 702a3b6170f57011e9ac6a5ee61874be9e0d90bd..fd0a5b00d29a2f2929325518f164cae06d45266f 100644 --- a/vendor/google.golang.org/grpc/examples/helloworld/greeter_server/main.go +++ b/vendor/google.golang.org/grpc/examples/helloworld/greeter_server/main.go @@ -21,10 +21,10 @@ package main import ( + "context" "log" "net" - "golang.org/x/net/context" "google.golang.org/grpc" pb "google.golang.org/grpc/examples/helloworld/helloworld" "google.golang.org/grpc/reflection" diff --git a/vendor/google.golang.org/grpc/examples/helloworld/mock_helloworld/hw_mock_test.go b/vendor/google.golang.org/grpc/examples/helloworld/mock_helloworld/hw_mock_test.go index 3966763313ef110335054e59bcdff91fa05ddcf2..358d13bda4d1f25ae6138ba7171fbf0b6d002181 100644 --- a/vendor/google.golang.org/grpc/examples/helloworld/mock_helloworld/hw_mock_test.go +++ b/vendor/google.golang.org/grpc/examples/helloworld/mock_helloworld/hw_mock_test.go @@ -19,13 +19,13 @@ package mock_helloworld_test import ( + "context" "fmt" "testing" "time" "github.com/golang/mock/gomock" "github.com/golang/protobuf/proto" - "golang.org/x/net/context" helloworld "google.golang.org/grpc/examples/helloworld/helloworld" hwmock "google.golang.org/grpc/examples/helloworld/mock_helloworld" ) diff --git a/vendor/google.golang.org/grpc/examples/oauth/client/main.go b/vendor/google.golang.org/grpc/examples/oauth/client/main.go index d167c43e62395b90cbb9e427e9d39b9d56e6a2b1..343a5ff7edf87f23693228c82c753e2bbbfeb9fb 100644 --- a/vendor/google.golang.org/grpc/examples/oauth/client/main.go +++ b/vendor/google.golang.org/grpc/examples/oauth/client/main.go @@ -20,11 +20,11 @@ package main import ( + "context" "crypto/tls" "log" "time" - "golang.org/x/net/context" "golang.org/x/oauth2" "google.golang.org/grpc" "google.golang.org/grpc/credentials" diff --git a/vendor/google.golang.org/grpc/examples/oauth/server/main.go b/vendor/google.golang.org/grpc/examples/oauth/server/main.go index 5135e9dcc711804a3265399792e0d99667acb336..517065c5cc6739911d1795d10f326d88802b66e1 100644 --- a/vendor/google.golang.org/grpc/examples/oauth/server/main.go +++ b/vendor/google.golang.org/grpc/examples/oauth/server/main.go @@ -21,12 +21,12 @@ package main import ( + "context" "crypto/tls" "log" "net" "strings" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" diff --git a/vendor/google.golang.org/grpc/examples/route_guide/client/client.go b/vendor/google.golang.org/grpc/examples/route_guide/client/client.go index 1ad1c1793430222563ba425bc2ba7f31212b4a28..29fb737851421c61e5046f20c5707340206382da 100644 --- a/vendor/google.golang.org/grpc/examples/route_guide/client/client.go +++ b/vendor/google.golang.org/grpc/examples/route_guide/client/client.go @@ -23,13 +23,13 @@ package main import ( + "context" "flag" "io" "log" "math/rand" "time" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/credentials" pb "google.golang.org/grpc/examples/route_guide/routeguide" diff --git a/vendor/google.golang.org/grpc/examples/route_guide/mock_routeguide/rg_mock_test.go b/vendor/google.golang.org/grpc/examples/route_guide/mock_routeguide/rg_mock_test.go index 8525cd5fd2fb7719c53026f76e9948795524f065..80f35524ddd775c347efee1c221dde20fa033416 100644 --- a/vendor/google.golang.org/grpc/examples/route_guide/mock_routeguide/rg_mock_test.go +++ b/vendor/google.golang.org/grpc/examples/route_guide/mock_routeguide/rg_mock_test.go @@ -19,13 +19,13 @@ package mock_routeguide_test import ( + "context" "fmt" "testing" "time" "github.com/golang/mock/gomock" "github.com/golang/protobuf/proto" - "golang.org/x/net/context" rgmock "google.golang.org/grpc/examples/route_guide/mock_routeguide" rgpb "google.golang.org/grpc/examples/route_guide/routeguide" ) diff --git a/vendor/google.golang.org/grpc/examples/route_guide/server/server.go b/vendor/google.golang.org/grpc/examples/route_guide/server/server.go index ececfa7e59ccbec2b25eb3df559e739fb4d21206..bd4278edaef4d1a296270d55db4932f50f8be547 100644 --- a/vendor/google.golang.org/grpc/examples/route_guide/server/server.go +++ b/vendor/google.golang.org/grpc/examples/route_guide/server/server.go @@ -25,6 +25,7 @@ package main import ( + "context" "encoding/json" "flag" "fmt" @@ -36,7 +37,6 @@ import ( "sync" "time" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/credentials" diff --git a/vendor/google.golang.org/grpc/examples/rpc_errors/client/main.go b/vendor/google.golang.org/grpc/examples/rpc_errors/client/main.go index b50fa8ce96417ea7e9a07bd23bb710895f18ac29..daccb1ef2e3d13c2290679acd4de15bbd3cbb69d 100644 --- a/vendor/google.golang.org/grpc/examples/rpc_errors/client/main.go +++ b/vendor/google.golang.org/grpc/examples/rpc_errors/client/main.go @@ -19,11 +19,11 @@ package main import ( + "context" "log" "os" "time" - "golang.org/x/net/context" epb "google.golang.org/genproto/googleapis/rpc/errdetails" "google.golang.org/grpc" pb "google.golang.org/grpc/examples/helloworld/helloworld" diff --git a/vendor/google.golang.org/grpc/examples/rpc_errors/server/main.go b/vendor/google.golang.org/grpc/examples/rpc_errors/server/main.go index ced95d3eff100d44f1e52c03c55af563838795f1..7593aabd10c02e15a5ec9ffe3b9130749182dcea 100644 --- a/vendor/google.golang.org/grpc/examples/rpc_errors/server/main.go +++ b/vendor/google.golang.org/grpc/examples/rpc_errors/server/main.go @@ -19,12 +19,12 @@ package main import ( + "context" "fmt" "log" "net" "sync" - "golang.org/x/net/context" epb "google.golang.org/genproto/googleapis/rpc/errdetails" "google.golang.org/grpc" "google.golang.org/grpc/codes" diff --git a/vendor/google.golang.org/grpc/go.mod b/vendor/google.golang.org/grpc/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..f296dcf4e6e45929aa7bb54b75c1d25360299078 --- /dev/null +++ b/vendor/google.golang.org/grpc/go.mod @@ -0,0 +1,20 @@ +module google.golang.org/grpc + +require ( + cloud.google.com/go v0.26.0 // indirect + github.com/client9/misspell v0.3.4 + github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b + github.com/golang/mock v1.1.1 + github.com/golang/protobuf v1.2.0 + github.com/kisielk/gotool v1.0.0 // indirect + golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3 + golang.org/x/net v0.0.0-20180826012351-8a410e7b638d + golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be + golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f // indirect + golang.org/x/sys v0.0.0-20180830151530-49385e6e1522 + golang.org/x/text v0.3.0 // indirect + golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52 + google.golang.org/appengine v1.1.0 // indirect + google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 + honnef.co/go/tools v0.0.0-20180728063816-88497007e858 +) diff --git a/vendor/google.golang.org/grpc/go.sum b/vendor/google.golang.org/grpc/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..bfb6bb7c0ed4d741764eb58a9b6723ca140e8f0d --- /dev/null +++ b/vendor/google.golang.org/grpc/go.sum @@ -0,0 +1,32 @@ +cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3 h1:x/bBzNauLQAlE3fLku/xy92Y8QwKX5HZymrMz2IiKFc= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d h1:g9qWBGx4puODJTMVyoPrpoxPFgVGd+z1DZwjfRu4d0I= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522 h1:Ve1ORMCxvRmSXBwJK+t3Oy+V2vRW2OetUQBq4rJIkZE= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52 h1:JG/0uqcGdTNgq7FdU+61l5Pdmb8putNZlXb65bJBROs= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858 h1:wN+eVZ7U+gqdqkec6C6VXR1OFf9a5Ul9ETzeYsYv20g= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/vendor/google.golang.org/grpc/go16.go b/vendor/google.golang.org/grpc/go16.go deleted file mode 100644 index 535ee9356f34f12ac60730f559ef3fb91b968def..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/go16.go +++ /dev/null @@ -1,70 +0,0 @@ -// +build go1.6,!go1.7 - -/* - * - * Copyright 2016 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package grpc - -import ( - "fmt" - "io" - "net" - "net/http" - - "golang.org/x/net/context" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "google.golang.org/grpc/transport" -) - -// dialContext connects to the address on the named network. -func dialContext(ctx context.Context, network, address string) (net.Conn, error) { - return (&net.Dialer{Cancel: ctx.Done()}).Dial(network, address) -} - -func sendHTTPRequest(ctx context.Context, req *http.Request, conn net.Conn) error { - req.Cancel = ctx.Done() - if err := req.Write(conn); err != nil { - return fmt.Errorf("failed to write the HTTP request: %v", err) - } - return nil -} - -// toRPCErr converts an error into an error from the status package. -func toRPCErr(err error) error { - if err == nil || err == io.EOF { - return err - } - if _, ok := status.FromError(err); ok { - return err - } - switch e := err.(type) { - case transport.StreamError: - return status.Error(e.Code, e.Desc) - case transport.ConnectionError: - return status.Error(codes.Unavailable, e.Desc) - default: - switch err { - case context.DeadlineExceeded: - return status.Error(codes.DeadlineExceeded, err.Error()) - case context.Canceled: - return status.Error(codes.Canceled, err.Error()) - } - } - return status.Error(codes.Unknown, err.Error()) -} diff --git a/vendor/google.golang.org/grpc/go17.go b/vendor/google.golang.org/grpc/go17.go deleted file mode 100644 index ec676a93c396ffa38b6d54ac8c1a28ea936e055c..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/go17.go +++ /dev/null @@ -1,71 +0,0 @@ -// +build go1.7 - -/* - * - * Copyright 2016 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package grpc - -import ( - "context" - "fmt" - "io" - "net" - "net/http" - - netctx "golang.org/x/net/context" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "google.golang.org/grpc/transport" -) - -// dialContext connects to the address on the named network. -func dialContext(ctx context.Context, network, address string) (net.Conn, error) { - return (&net.Dialer{}).DialContext(ctx, network, address) -} - -func sendHTTPRequest(ctx context.Context, req *http.Request, conn net.Conn) error { - req = req.WithContext(ctx) - if err := req.Write(conn); err != nil { - return fmt.Errorf("failed to write the HTTP request: %v", err) - } - return nil -} - -// toRPCErr converts an error into an error from the status package. -func toRPCErr(err error) error { - if err == nil || err == io.EOF { - return err - } - if _, ok := status.FromError(err); ok { - return err - } - switch e := err.(type) { - case transport.StreamError: - return status.Error(e.Code, e.Desc) - case transport.ConnectionError: - return status.Error(codes.Unavailable, e.Desc) - default: - switch err { - case context.DeadlineExceeded, netctx.DeadlineExceeded: - return status.Error(codes.DeadlineExceeded, err.Error()) - case context.Canceled, netctx.Canceled: - return status.Error(codes.Canceled, err.Error()) - } - } - return status.Error(codes.Unknown, err.Error()) -} diff --git a/vendor/google.golang.org/grpc/grpclb/grpc_lb_v1/messages/messages.pb.go b/vendor/google.golang.org/grpc/grpclb/grpc_lb_v1/messages/messages.pb.go deleted file mode 100644 index 59b1ed4ca60df988d0ef88309a377589cb2f01e5..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/grpclb/grpc_lb_v1/messages/messages.pb.go +++ /dev/null @@ -1,718 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: grpc_lb_v1/messages/messages.proto - -package messages // import "google.golang.org/grpc/grpclb/grpc_lb_v1/messages" - -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" -import duration "github.com/golang/protobuf/ptypes/duration" -import timestamp "github.com/golang/protobuf/ptypes/timestamp" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package - -type LoadBalanceRequest struct { - // Types that are valid to be assigned to LoadBalanceRequestType: - // *LoadBalanceRequest_InitialRequest - // *LoadBalanceRequest_ClientStats - LoadBalanceRequestType isLoadBalanceRequest_LoadBalanceRequestType `protobuf_oneof:"load_balance_request_type"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *LoadBalanceRequest) Reset() { *m = LoadBalanceRequest{} } -func (m *LoadBalanceRequest) String() string { return proto.CompactTextString(m) } -func (*LoadBalanceRequest) ProtoMessage() {} -func (*LoadBalanceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_messages_b3d89fcb5aa158f8, []int{0} -} -func (m *LoadBalanceRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_LoadBalanceRequest.Unmarshal(m, b) -} -func (m *LoadBalanceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_LoadBalanceRequest.Marshal(b, m, deterministic) -} -func (dst *LoadBalanceRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_LoadBalanceRequest.Merge(dst, src) -} -func (m *LoadBalanceRequest) XXX_Size() int { - return xxx_messageInfo_LoadBalanceRequest.Size(m) -} -func (m *LoadBalanceRequest) XXX_DiscardUnknown() { - xxx_messageInfo_LoadBalanceRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_LoadBalanceRequest proto.InternalMessageInfo - -type isLoadBalanceRequest_LoadBalanceRequestType interface { - isLoadBalanceRequest_LoadBalanceRequestType() -} - -type LoadBalanceRequest_InitialRequest struct { - InitialRequest *InitialLoadBalanceRequest `protobuf:"bytes,1,opt,name=initial_request,json=initialRequest,proto3,oneof"` -} -type LoadBalanceRequest_ClientStats struct { - ClientStats *ClientStats `protobuf:"bytes,2,opt,name=client_stats,json=clientStats,proto3,oneof"` -} - -func (*LoadBalanceRequest_InitialRequest) isLoadBalanceRequest_LoadBalanceRequestType() {} -func (*LoadBalanceRequest_ClientStats) isLoadBalanceRequest_LoadBalanceRequestType() {} - -func (m *LoadBalanceRequest) GetLoadBalanceRequestType() isLoadBalanceRequest_LoadBalanceRequestType { - if m != nil { - return m.LoadBalanceRequestType - } - return nil -} - -func (m *LoadBalanceRequest) GetInitialRequest() *InitialLoadBalanceRequest { - if x, ok := m.GetLoadBalanceRequestType().(*LoadBalanceRequest_InitialRequest); ok { - return x.InitialRequest - } - return nil -} - -func (m *LoadBalanceRequest) GetClientStats() *ClientStats { - if x, ok := m.GetLoadBalanceRequestType().(*LoadBalanceRequest_ClientStats); ok { - return x.ClientStats - } - return nil -} - -// XXX_OneofFuncs is for the internal use of the proto package. -func (*LoadBalanceRequest) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { - return _LoadBalanceRequest_OneofMarshaler, _LoadBalanceRequest_OneofUnmarshaler, _LoadBalanceRequest_OneofSizer, []interface{}{ - (*LoadBalanceRequest_InitialRequest)(nil), - (*LoadBalanceRequest_ClientStats)(nil), - } -} - -func _LoadBalanceRequest_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { - m := msg.(*LoadBalanceRequest) - // load_balance_request_type - switch x := m.LoadBalanceRequestType.(type) { - case *LoadBalanceRequest_InitialRequest: - b.EncodeVarint(1<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.InitialRequest); err != nil { - return err - } - case *LoadBalanceRequest_ClientStats: - b.EncodeVarint(2<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.ClientStats); err != nil { - return err - } - case nil: - default: - return fmt.Errorf("LoadBalanceRequest.LoadBalanceRequestType has unexpected type %T", x) - } - return nil -} - -func _LoadBalanceRequest_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { - m := msg.(*LoadBalanceRequest) - switch tag { - case 1: // load_balance_request_type.initial_request - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(InitialLoadBalanceRequest) - err := b.DecodeMessage(msg) - m.LoadBalanceRequestType = &LoadBalanceRequest_InitialRequest{msg} - return true, err - case 2: // load_balance_request_type.client_stats - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(ClientStats) - err := b.DecodeMessage(msg) - m.LoadBalanceRequestType = &LoadBalanceRequest_ClientStats{msg} - return true, err - default: - return false, nil - } -} - -func _LoadBalanceRequest_OneofSizer(msg proto.Message) (n int) { - m := msg.(*LoadBalanceRequest) - // load_balance_request_type - switch x := m.LoadBalanceRequestType.(type) { - case *LoadBalanceRequest_InitialRequest: - s := proto.Size(x.InitialRequest) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case *LoadBalanceRequest_ClientStats: - s := proto.Size(x.ClientStats) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case nil: - default: - panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) - } - return n -} - -type InitialLoadBalanceRequest struct { - // Name of load balanced service (IE, balancer.service.com). Its - // length should be less than 256 bytes. - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *InitialLoadBalanceRequest) Reset() { *m = InitialLoadBalanceRequest{} } -func (m *InitialLoadBalanceRequest) String() string { return proto.CompactTextString(m) } -func (*InitialLoadBalanceRequest) ProtoMessage() {} -func (*InitialLoadBalanceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_messages_b3d89fcb5aa158f8, []int{1} -} -func (m *InitialLoadBalanceRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_InitialLoadBalanceRequest.Unmarshal(m, b) -} -func (m *InitialLoadBalanceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_InitialLoadBalanceRequest.Marshal(b, m, deterministic) -} -func (dst *InitialLoadBalanceRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_InitialLoadBalanceRequest.Merge(dst, src) -} -func (m *InitialLoadBalanceRequest) XXX_Size() int { - return xxx_messageInfo_InitialLoadBalanceRequest.Size(m) -} -func (m *InitialLoadBalanceRequest) XXX_DiscardUnknown() { - xxx_messageInfo_InitialLoadBalanceRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_InitialLoadBalanceRequest proto.InternalMessageInfo - -func (m *InitialLoadBalanceRequest) GetName() string { - if m != nil { - return m.Name - } - return "" -} - -// Contains the number of calls finished for a particular load balance token. -type ClientStatsPerToken struct { - // See Server.load_balance_token. - LoadBalanceToken string `protobuf:"bytes,1,opt,name=load_balance_token,json=loadBalanceToken,proto3" json:"load_balance_token,omitempty"` - // The total number of RPCs that finished associated with the token. - NumCalls int64 `protobuf:"varint,2,opt,name=num_calls,json=numCalls,proto3" json:"num_calls,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ClientStatsPerToken) Reset() { *m = ClientStatsPerToken{} } -func (m *ClientStatsPerToken) String() string { return proto.CompactTextString(m) } -func (*ClientStatsPerToken) ProtoMessage() {} -func (*ClientStatsPerToken) Descriptor() ([]byte, []int) { - return fileDescriptor_messages_b3d89fcb5aa158f8, []int{2} -} -func (m *ClientStatsPerToken) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ClientStatsPerToken.Unmarshal(m, b) -} -func (m *ClientStatsPerToken) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ClientStatsPerToken.Marshal(b, m, deterministic) -} -func (dst *ClientStatsPerToken) XXX_Merge(src proto.Message) { - xxx_messageInfo_ClientStatsPerToken.Merge(dst, src) -} -func (m *ClientStatsPerToken) XXX_Size() int { - return xxx_messageInfo_ClientStatsPerToken.Size(m) -} -func (m *ClientStatsPerToken) XXX_DiscardUnknown() { - xxx_messageInfo_ClientStatsPerToken.DiscardUnknown(m) -} - -var xxx_messageInfo_ClientStatsPerToken proto.InternalMessageInfo - -func (m *ClientStatsPerToken) GetLoadBalanceToken() string { - if m != nil { - return m.LoadBalanceToken - } - return "" -} - -func (m *ClientStatsPerToken) GetNumCalls() int64 { - if m != nil { - return m.NumCalls - } - return 0 -} - -// Contains client level statistics that are useful to load balancing. Each -// count except the timestamp should be reset to zero after reporting the stats. -type ClientStats struct { - // The timestamp of generating the report. - Timestamp *timestamp.Timestamp `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - // The total number of RPCs that started. - NumCallsStarted int64 `protobuf:"varint,2,opt,name=num_calls_started,json=numCallsStarted,proto3" json:"num_calls_started,omitempty"` - // The total number of RPCs that finished. - NumCallsFinished int64 `protobuf:"varint,3,opt,name=num_calls_finished,json=numCallsFinished,proto3" json:"num_calls_finished,omitempty"` - // The total number of RPCs that failed to reach a server except dropped RPCs. - NumCallsFinishedWithClientFailedToSend int64 `protobuf:"varint,6,opt,name=num_calls_finished_with_client_failed_to_send,json=numCallsFinishedWithClientFailedToSend,proto3" json:"num_calls_finished_with_client_failed_to_send,omitempty"` - // The total number of RPCs that finished and are known to have been received - // by a server. - NumCallsFinishedKnownReceived int64 `protobuf:"varint,7,opt,name=num_calls_finished_known_received,json=numCallsFinishedKnownReceived,proto3" json:"num_calls_finished_known_received,omitempty"` - // The list of dropped calls. - CallsFinishedWithDrop []*ClientStatsPerToken `protobuf:"bytes,8,rep,name=calls_finished_with_drop,json=callsFinishedWithDrop,proto3" json:"calls_finished_with_drop,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ClientStats) Reset() { *m = ClientStats{} } -func (m *ClientStats) String() string { return proto.CompactTextString(m) } -func (*ClientStats) ProtoMessage() {} -func (*ClientStats) Descriptor() ([]byte, []int) { - return fileDescriptor_messages_b3d89fcb5aa158f8, []int{3} -} -func (m *ClientStats) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ClientStats.Unmarshal(m, b) -} -func (m *ClientStats) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ClientStats.Marshal(b, m, deterministic) -} -func (dst *ClientStats) XXX_Merge(src proto.Message) { - xxx_messageInfo_ClientStats.Merge(dst, src) -} -func (m *ClientStats) XXX_Size() int { - return xxx_messageInfo_ClientStats.Size(m) -} -func (m *ClientStats) XXX_DiscardUnknown() { - xxx_messageInfo_ClientStats.DiscardUnknown(m) -} - -var xxx_messageInfo_ClientStats proto.InternalMessageInfo - -func (m *ClientStats) GetTimestamp() *timestamp.Timestamp { - if m != nil { - return m.Timestamp - } - return nil -} - -func (m *ClientStats) GetNumCallsStarted() int64 { - if m != nil { - return m.NumCallsStarted - } - return 0 -} - -func (m *ClientStats) GetNumCallsFinished() int64 { - if m != nil { - return m.NumCallsFinished - } - return 0 -} - -func (m *ClientStats) GetNumCallsFinishedWithClientFailedToSend() int64 { - if m != nil { - return m.NumCallsFinishedWithClientFailedToSend - } - return 0 -} - -func (m *ClientStats) GetNumCallsFinishedKnownReceived() int64 { - if m != nil { - return m.NumCallsFinishedKnownReceived - } - return 0 -} - -func (m *ClientStats) GetCallsFinishedWithDrop() []*ClientStatsPerToken { - if m != nil { - return m.CallsFinishedWithDrop - } - return nil -} - -type LoadBalanceResponse struct { - // Types that are valid to be assigned to LoadBalanceResponseType: - // *LoadBalanceResponse_InitialResponse - // *LoadBalanceResponse_ServerList - LoadBalanceResponseType isLoadBalanceResponse_LoadBalanceResponseType `protobuf_oneof:"load_balance_response_type"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *LoadBalanceResponse) Reset() { *m = LoadBalanceResponse{} } -func (m *LoadBalanceResponse) String() string { return proto.CompactTextString(m) } -func (*LoadBalanceResponse) ProtoMessage() {} -func (*LoadBalanceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_messages_b3d89fcb5aa158f8, []int{4} -} -func (m *LoadBalanceResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_LoadBalanceResponse.Unmarshal(m, b) -} -func (m *LoadBalanceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_LoadBalanceResponse.Marshal(b, m, deterministic) -} -func (dst *LoadBalanceResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_LoadBalanceResponse.Merge(dst, src) -} -func (m *LoadBalanceResponse) XXX_Size() int { - return xxx_messageInfo_LoadBalanceResponse.Size(m) -} -func (m *LoadBalanceResponse) XXX_DiscardUnknown() { - xxx_messageInfo_LoadBalanceResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_LoadBalanceResponse proto.InternalMessageInfo - -type isLoadBalanceResponse_LoadBalanceResponseType interface { - isLoadBalanceResponse_LoadBalanceResponseType() -} - -type LoadBalanceResponse_InitialResponse struct { - InitialResponse *InitialLoadBalanceResponse `protobuf:"bytes,1,opt,name=initial_response,json=initialResponse,proto3,oneof"` -} -type LoadBalanceResponse_ServerList struct { - ServerList *ServerList `protobuf:"bytes,2,opt,name=server_list,json=serverList,proto3,oneof"` -} - -func (*LoadBalanceResponse_InitialResponse) isLoadBalanceResponse_LoadBalanceResponseType() {} -func (*LoadBalanceResponse_ServerList) isLoadBalanceResponse_LoadBalanceResponseType() {} - -func (m *LoadBalanceResponse) GetLoadBalanceResponseType() isLoadBalanceResponse_LoadBalanceResponseType { - if m != nil { - return m.LoadBalanceResponseType - } - return nil -} - -func (m *LoadBalanceResponse) GetInitialResponse() *InitialLoadBalanceResponse { - if x, ok := m.GetLoadBalanceResponseType().(*LoadBalanceResponse_InitialResponse); ok { - return x.InitialResponse - } - return nil -} - -func (m *LoadBalanceResponse) GetServerList() *ServerList { - if x, ok := m.GetLoadBalanceResponseType().(*LoadBalanceResponse_ServerList); ok { - return x.ServerList - } - return nil -} - -// XXX_OneofFuncs is for the internal use of the proto package. -func (*LoadBalanceResponse) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { - return _LoadBalanceResponse_OneofMarshaler, _LoadBalanceResponse_OneofUnmarshaler, _LoadBalanceResponse_OneofSizer, []interface{}{ - (*LoadBalanceResponse_InitialResponse)(nil), - (*LoadBalanceResponse_ServerList)(nil), - } -} - -func _LoadBalanceResponse_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { - m := msg.(*LoadBalanceResponse) - // load_balance_response_type - switch x := m.LoadBalanceResponseType.(type) { - case *LoadBalanceResponse_InitialResponse: - b.EncodeVarint(1<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.InitialResponse); err != nil { - return err - } - case *LoadBalanceResponse_ServerList: - b.EncodeVarint(2<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.ServerList); err != nil { - return err - } - case nil: - default: - return fmt.Errorf("LoadBalanceResponse.LoadBalanceResponseType has unexpected type %T", x) - } - return nil -} - -func _LoadBalanceResponse_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { - m := msg.(*LoadBalanceResponse) - switch tag { - case 1: // load_balance_response_type.initial_response - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(InitialLoadBalanceResponse) - err := b.DecodeMessage(msg) - m.LoadBalanceResponseType = &LoadBalanceResponse_InitialResponse{msg} - return true, err - case 2: // load_balance_response_type.server_list - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(ServerList) - err := b.DecodeMessage(msg) - m.LoadBalanceResponseType = &LoadBalanceResponse_ServerList{msg} - return true, err - default: - return false, nil - } -} - -func _LoadBalanceResponse_OneofSizer(msg proto.Message) (n int) { - m := msg.(*LoadBalanceResponse) - // load_balance_response_type - switch x := m.LoadBalanceResponseType.(type) { - case *LoadBalanceResponse_InitialResponse: - s := proto.Size(x.InitialResponse) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case *LoadBalanceResponse_ServerList: - s := proto.Size(x.ServerList) - n += 1 // tag and wire - n += proto.SizeVarint(uint64(s)) - n += s - case nil: - default: - panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) - } - return n -} - -type InitialLoadBalanceResponse struct { - // This is an application layer redirect that indicates the client should use - // the specified server for load balancing. When this field is non-empty in - // the response, the client should open a separate connection to the - // load_balancer_delegate and call the BalanceLoad method. Its length should - // be less than 64 bytes. - LoadBalancerDelegate string `protobuf:"bytes,1,opt,name=load_balancer_delegate,json=loadBalancerDelegate,proto3" json:"load_balancer_delegate,omitempty"` - // This interval defines how often the client should send the client stats - // to the load balancer. Stats should only be reported when the duration is - // positive. - ClientStatsReportInterval *duration.Duration `protobuf:"bytes,2,opt,name=client_stats_report_interval,json=clientStatsReportInterval,proto3" json:"client_stats_report_interval,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *InitialLoadBalanceResponse) Reset() { *m = InitialLoadBalanceResponse{} } -func (m *InitialLoadBalanceResponse) String() string { return proto.CompactTextString(m) } -func (*InitialLoadBalanceResponse) ProtoMessage() {} -func (*InitialLoadBalanceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_messages_b3d89fcb5aa158f8, []int{5} -} -func (m *InitialLoadBalanceResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_InitialLoadBalanceResponse.Unmarshal(m, b) -} -func (m *InitialLoadBalanceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_InitialLoadBalanceResponse.Marshal(b, m, deterministic) -} -func (dst *InitialLoadBalanceResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_InitialLoadBalanceResponse.Merge(dst, src) -} -func (m *InitialLoadBalanceResponse) XXX_Size() int { - return xxx_messageInfo_InitialLoadBalanceResponse.Size(m) -} -func (m *InitialLoadBalanceResponse) XXX_DiscardUnknown() { - xxx_messageInfo_InitialLoadBalanceResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_InitialLoadBalanceResponse proto.InternalMessageInfo - -func (m *InitialLoadBalanceResponse) GetLoadBalancerDelegate() string { - if m != nil { - return m.LoadBalancerDelegate - } - return "" -} - -func (m *InitialLoadBalanceResponse) GetClientStatsReportInterval() *duration.Duration { - if m != nil { - return m.ClientStatsReportInterval - } - return nil -} - -type ServerList struct { - // Contains a list of servers selected by the load balancer. The list will - // be updated when server resolutions change or as needed to balance load - // across more servers. The client should consume the server list in order - // unless instructed otherwise via the client_config. - Servers []*Server `protobuf:"bytes,1,rep,name=servers,proto3" json:"servers,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ServerList) Reset() { *m = ServerList{} } -func (m *ServerList) String() string { return proto.CompactTextString(m) } -func (*ServerList) ProtoMessage() {} -func (*ServerList) Descriptor() ([]byte, []int) { - return fileDescriptor_messages_b3d89fcb5aa158f8, []int{6} -} -func (m *ServerList) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ServerList.Unmarshal(m, b) -} -func (m *ServerList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ServerList.Marshal(b, m, deterministic) -} -func (dst *ServerList) XXX_Merge(src proto.Message) { - xxx_messageInfo_ServerList.Merge(dst, src) -} -func (m *ServerList) XXX_Size() int { - return xxx_messageInfo_ServerList.Size(m) -} -func (m *ServerList) XXX_DiscardUnknown() { - xxx_messageInfo_ServerList.DiscardUnknown(m) -} - -var xxx_messageInfo_ServerList proto.InternalMessageInfo - -func (m *ServerList) GetServers() []*Server { - if m != nil { - return m.Servers - } - return nil -} - -// Contains server information. When the drop field is not true, use the other -// fields. -type Server struct { - // A resolved address for the server, serialized in network-byte-order. It may - // either be an IPv4 or IPv6 address. - IpAddress []byte `protobuf:"bytes,1,opt,name=ip_address,json=ipAddress,proto3" json:"ip_address,omitempty"` - // A resolved port number for the server. - Port int32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"` - // An opaque but printable token given to the frontend for each pick. All - // frontend requests for that pick must include the token in its initial - // metadata. The token is used by the backend to verify the request and to - // allow the backend to report load to the gRPC LB system. The token is also - // used in client stats for reporting dropped calls. - LoadBalanceToken string `protobuf:"bytes,3,opt,name=load_balance_token,json=loadBalanceToken,proto3" json:"load_balance_token,omitempty"` - // Indicates whether this particular request should be dropped by the client. - // If the request is dropped, there will be a corresponding entry in - // ClientStats.calls_finished_with_drop. - Drop bool `protobuf:"varint,4,opt,name=drop,proto3" json:"drop,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Server) Reset() { *m = Server{} } -func (m *Server) String() string { return proto.CompactTextString(m) } -func (*Server) ProtoMessage() {} -func (*Server) Descriptor() ([]byte, []int) { - return fileDescriptor_messages_b3d89fcb5aa158f8, []int{7} -} -func (m *Server) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Server.Unmarshal(m, b) -} -func (m *Server) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Server.Marshal(b, m, deterministic) -} -func (dst *Server) XXX_Merge(src proto.Message) { - xxx_messageInfo_Server.Merge(dst, src) -} -func (m *Server) XXX_Size() int { - return xxx_messageInfo_Server.Size(m) -} -func (m *Server) XXX_DiscardUnknown() { - xxx_messageInfo_Server.DiscardUnknown(m) -} - -var xxx_messageInfo_Server proto.InternalMessageInfo - -func (m *Server) GetIpAddress() []byte { - if m != nil { - return m.IpAddress - } - return nil -} - -func (m *Server) GetPort() int32 { - if m != nil { - return m.Port - } - return 0 -} - -func (m *Server) GetLoadBalanceToken() string { - if m != nil { - return m.LoadBalanceToken - } - return "" -} - -func (m *Server) GetDrop() bool { - if m != nil { - return m.Drop - } - return false -} - -func init() { - proto.RegisterType((*LoadBalanceRequest)(nil), "grpc.lb.v1.LoadBalanceRequest") - proto.RegisterType((*InitialLoadBalanceRequest)(nil), "grpc.lb.v1.InitialLoadBalanceRequest") - proto.RegisterType((*ClientStatsPerToken)(nil), "grpc.lb.v1.ClientStatsPerToken") - proto.RegisterType((*ClientStats)(nil), "grpc.lb.v1.ClientStats") - proto.RegisterType((*LoadBalanceResponse)(nil), "grpc.lb.v1.LoadBalanceResponse") - proto.RegisterType((*InitialLoadBalanceResponse)(nil), "grpc.lb.v1.InitialLoadBalanceResponse") - proto.RegisterType((*ServerList)(nil), "grpc.lb.v1.ServerList") - proto.RegisterType((*Server)(nil), "grpc.lb.v1.Server") -} - -func init() { - proto.RegisterFile("grpc_lb_v1/messages/messages.proto", fileDescriptor_messages_b3d89fcb5aa158f8) -} - -var fileDescriptor_messages_b3d89fcb5aa158f8 = []byte{ - // 708 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x54, 0x61, 0x4f, 0xf3, 0x36, - 0x10, 0x26, 0x6b, 0xe8, 0xdb, 0x5e, 0x5f, 0x8d, 0xce, 0x6c, 0x2c, 0x2d, 0x30, 0x58, 0xa4, 0x21, - 0x34, 0xb1, 0x54, 0xc0, 0x3e, 0x6c, 0xd2, 0x3e, 0x6c, 0x05, 0xa1, 0xc2, 0xf8, 0x80, 0x52, 0xa4, - 0x4d, 0x48, 0x93, 0xe7, 0x36, 0x26, 0x58, 0xb8, 0x76, 0x66, 0xbb, 0x45, 0xfb, 0xbc, 0xff, 0x33, - 0xed, 0x2f, 0x4c, 0xfb, 0x63, 0x53, 0xec, 0xa4, 0x0d, 0x2d, 0xd5, 0xfb, 0x25, 0x72, 0xee, 0x9e, - 0x7b, 0xee, 0xce, 0x77, 0x8f, 0x21, 0x4c, 0x55, 0x36, 0xc6, 0x7c, 0x84, 0x67, 0xa7, 0xbd, 0x09, - 0xd5, 0x9a, 0xa4, 0x54, 0xcf, 0x0f, 0x51, 0xa6, 0xa4, 0x91, 0x08, 0x72, 0x4c, 0xc4, 0x47, 0xd1, - 0xec, 0xb4, 0xfb, 0x45, 0x2a, 0x65, 0xca, 0x69, 0xcf, 0x7a, 0x46, 0xd3, 0xc7, 0x5e, 0x32, 0x55, - 0xc4, 0x30, 0x29, 0x1c, 0xb6, 0x7b, 0xb0, 0xec, 0x37, 0x6c, 0x42, 0xb5, 0x21, 0x93, 0xcc, 0x01, - 0xc2, 0x7f, 0x3d, 0x40, 0xb7, 0x92, 0x24, 0x7d, 0xc2, 0x89, 0x18, 0xd3, 0x98, 0xfe, 0x31, 0xa5, - 0xda, 0xa0, 0x3b, 0xd8, 0x62, 0x82, 0x19, 0x46, 0x38, 0x56, 0xce, 0x14, 0x78, 0x87, 0xde, 0x71, - 0xeb, 0xec, 0xab, 0x68, 0x91, 0x3d, 0xba, 0x76, 0x90, 0xd5, 0xf8, 0xc1, 0x46, 0xfc, 0x71, 0x11, - 0x5f, 0x32, 0xfe, 0x00, 0xef, 0xc7, 0x9c, 0x51, 0x61, 0xb0, 0x36, 0xc4, 0xe8, 0xe0, 0x23, 0x4b, - 0xf7, 0x79, 0x95, 0xee, 0xc2, 0xfa, 0x87, 0xb9, 0x7b, 0xb0, 0x11, 0xb7, 0xc6, 0x8b, 0xdf, 0xfe, - 0x2e, 0x74, 0xb8, 0x24, 0x09, 0x1e, 0xb9, 0x34, 0x65, 0x51, 0xd8, 0xfc, 0x99, 0xd1, 0xb0, 0x07, - 0x9d, 0xb5, 0x95, 0x20, 0x04, 0xbe, 0x20, 0x13, 0x6a, 0xcb, 0x6f, 0xc6, 0xf6, 0x1c, 0xfe, 0x0e, - 0xdb, 0x95, 0x5c, 0x77, 0x54, 0xdd, 0xcb, 0x67, 0x2a, 0xd0, 0x09, 0xa0, 0x57, 0x49, 0x4c, 0x6e, - 0x2d, 0x02, 0xdb, 0x7c, 0x41, 0xed, 0xd0, 0xbb, 0xd0, 0x14, 0xd3, 0x09, 0x1e, 0x13, 0xce, 0x5d, - 0x37, 0xb5, 0xb8, 0x21, 0xa6, 0x93, 0x8b, 0xfc, 0x3f, 0xfc, 0xa7, 0x06, 0xad, 0x4a, 0x0a, 0xf4, - 0x1d, 0x34, 0xe7, 0x37, 0x5f, 0xdc, 0x64, 0x37, 0x72, 0xb3, 0x89, 0xca, 0xd9, 0x44, 0xf7, 0x25, - 0x22, 0x5e, 0x80, 0xd1, 0xd7, 0xf0, 0xc9, 0x3c, 0x4d, 0x7e, 0x75, 0xca, 0xd0, 0xa4, 0x48, 0xb7, - 0x55, 0xa6, 0x1b, 0x3a, 0x73, 0xde, 0xc0, 0x02, 0xfb, 0xc8, 0x04, 0xd3, 0x4f, 0x34, 0x09, 0x6a, - 0x16, 0xdc, 0x2e, 0xc1, 0x57, 0x85, 0x1d, 0xfd, 0x06, 0xdf, 0xac, 0xa2, 0xf1, 0x0b, 0x33, 0x4f, - 0xb8, 0x98, 0xd4, 0x23, 0x61, 0x9c, 0x26, 0xd8, 0x48, 0xac, 0xa9, 0x48, 0x82, 0xba, 0x25, 0x3a, - 0x5a, 0x26, 0xfa, 0x85, 0x99, 0x27, 0xd7, 0xeb, 0x95, 0xc5, 0xdf, 0xcb, 0x21, 0x15, 0x09, 0x1a, - 0xc0, 0x97, 0x6f, 0xd0, 0x3f, 0x0b, 0xf9, 0x22, 0xb0, 0xa2, 0x63, 0xca, 0x66, 0x34, 0x09, 0xde, - 0x59, 0xca, 0xfd, 0x65, 0xca, 0x9f, 0x73, 0x54, 0x5c, 0x80, 0xd0, 0xaf, 0x10, 0xbc, 0x55, 0x64, - 0xa2, 0x64, 0x16, 0x34, 0x0e, 0x6b, 0xc7, 0xad, 0xb3, 0x83, 0x35, 0x6b, 0x54, 0x8e, 0x36, 0xfe, - 0x6c, 0xbc, 0x5c, 0xf1, 0xa5, 0x92, 0xd9, 0x8d, 0xdf, 0xf0, 0xdb, 0x9b, 0x37, 0x7e, 0x63, 0xb3, - 0x5d, 0x0f, 0xff, 0xf3, 0x60, 0xfb, 0xd5, 0xfe, 0xe8, 0x4c, 0x0a, 0x4d, 0xd1, 0x10, 0xda, 0x0b, - 0x29, 0x38, 0x5b, 0x31, 0xc1, 0xa3, 0x0f, 0x69, 0xc1, 0xa1, 0x07, 0x1b, 0xf1, 0xd6, 0x5c, 0x0c, - 0x05, 0xe9, 0xf7, 0xd0, 0xd2, 0x54, 0xcd, 0xa8, 0xc2, 0x9c, 0x69, 0x53, 0x88, 0x61, 0xa7, 0xca, - 0x37, 0xb4, 0xee, 0x5b, 0x66, 0xc5, 0x04, 0x7a, 0xfe, 0xd7, 0xdf, 0x83, 0xee, 0x92, 0x14, 0x1c, - 0xa7, 0xd3, 0xc2, 0xdf, 0x1e, 0x74, 0xd7, 0x97, 0x82, 0xbe, 0x85, 0x9d, 0x6a, 0xb0, 0xc2, 0x09, - 0xe5, 0x34, 0x25, 0xa6, 0xd4, 0xc7, 0xa7, 0x95, 0x35, 0x57, 0x97, 0x85, 0x0f, 0x3d, 0xc0, 0x5e, - 0x55, 0xbb, 0x58, 0xd1, 0x4c, 0x2a, 0x83, 0x99, 0x30, 0x54, 0xcd, 0x08, 0x2f, 0xca, 0xef, 0xac, - 0x2c, 0xf4, 0x65, 0xf1, 0x18, 0xc5, 0x9d, 0x8a, 0x96, 0x63, 0x1b, 0x7c, 0x5d, 0xc4, 0x86, 0x3f, - 0x02, 0x2c, 0x5a, 0x45, 0x27, 0xf0, 0xce, 0xb5, 0xaa, 0x03, 0xcf, 0x4e, 0x16, 0xad, 0xde, 0x49, - 0x5c, 0x42, 0x6e, 0xfc, 0x46, 0xad, 0xed, 0x87, 0x7f, 0x79, 0x50, 0x77, 0x1e, 0xb4, 0x0f, 0xc0, - 0x32, 0x4c, 0x92, 0x44, 0x51, 0xad, 0x6d, 0x4b, 0xef, 0xe3, 0x26, 0xcb, 0x7e, 0x72, 0x86, 0xfc, - 0x2d, 0xc8, 0x73, 0xdb, 0x7a, 0x37, 0x63, 0x7b, 0x5e, 0x23, 0xfa, 0xda, 0x1a, 0xd1, 0x23, 0xf0, - 0xed, 0xda, 0xf9, 0x87, 0xde, 0x71, 0x23, 0xb6, 0x67, 0xb7, 0x3e, 0xfd, 0xf3, 0x87, 0xd3, 0xa2, - 0xfd, 0x54, 0x72, 0x22, 0xd2, 0x48, 0xaa, 0xb4, 0x97, 0xd7, 0x6e, 0x3f, 0x7c, 0xd4, 0x7b, 0xe3, - 0x65, 0x1f, 0xd5, 0xed, 0x55, 0x9d, 0xff, 0x1f, 0x00, 0x00, 0xff, 0xff, 0xc8, 0x88, 0xe6, 0xf4, - 0xf7, 0x05, 0x00, 0x00, -} diff --git a/vendor/google.golang.org/grpc/grpclb/grpc_lb_v1/messages/messages.proto b/vendor/google.golang.org/grpc/grpclb/grpc_lb_v1/messages/messages.proto deleted file mode 100644 index 56d767e543406823d6495d75befb4ed47fe5e7e2..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/grpclb/grpc_lb_v1/messages/messages.proto +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2016 gRPC authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -import "google/protobuf/duration.proto"; -import "google/protobuf/timestamp.proto"; - -package grpc.lb.v1; -option go_package = "google.golang.org/grpc/grpclb/grpc_lb_v1/messages"; - -message LoadBalanceRequest { - oneof load_balance_request_type { - // This message should be sent on the first request to the load balancer. - InitialLoadBalanceRequest initial_request = 1; - - // The client stats should be periodically reported to the load balancer - // based on the duration defined in the InitialLoadBalanceResponse. - ClientStats client_stats = 2; - } -} - -message InitialLoadBalanceRequest { - // Name of load balanced service (IE, balancer.service.com). Its - // length should be less than 256 bytes. - string name = 1; -} - -// Contains the number of calls finished for a particular load balance token. -message ClientStatsPerToken { - // See Server.load_balance_token. - string load_balance_token = 1; - - // The total number of RPCs that finished associated with the token. - int64 num_calls = 2; -} - -// Contains client level statistics that are useful to load balancing. Each -// count except the timestamp should be reset to zero after reporting the stats. -message ClientStats { - // The timestamp of generating the report. - google.protobuf.Timestamp timestamp = 1; - - // The total number of RPCs that started. - int64 num_calls_started = 2; - - // The total number of RPCs that finished. - int64 num_calls_finished = 3; - - // The total number of RPCs that failed to reach a server except dropped RPCs. - int64 num_calls_finished_with_client_failed_to_send = 6; - - // The total number of RPCs that finished and are known to have been received - // by a server. - int64 num_calls_finished_known_received = 7; - - // The list of dropped calls. - repeated ClientStatsPerToken calls_finished_with_drop = 8; - - reserved 4, 5; -} - -message LoadBalanceResponse { - oneof load_balance_response_type { - // This message should be sent on the first response to the client. - InitialLoadBalanceResponse initial_response = 1; - - // Contains the list of servers selected by the load balancer. The client - // should send requests to these servers in the specified order. - ServerList server_list = 2; - } -} - -message InitialLoadBalanceResponse { - // This is an application layer redirect that indicates the client should use - // the specified server for load balancing. When this field is non-empty in - // the response, the client should open a separate connection to the - // load_balancer_delegate and call the BalanceLoad method. Its length should - // be less than 64 bytes. - string load_balancer_delegate = 1; - - // This interval defines how often the client should send the client stats - // to the load balancer. Stats should only be reported when the duration is - // positive. - google.protobuf.Duration client_stats_report_interval = 2; -} - -message ServerList { - // Contains a list of servers selected by the load balancer. The list will - // be updated when server resolutions change or as needed to balance load - // across more servers. The client should consume the server list in order - // unless instructed otherwise via the client_config. - repeated Server servers = 1; - - // Was google.protobuf.Duration expiration_interval. - reserved 3; -} - -// Contains server information. When the drop field is not true, use the other -// fields. -message Server { - // A resolved address for the server, serialized in network-byte-order. It may - // either be an IPv4 or IPv6 address. - bytes ip_address = 1; - - // A resolved port number for the server. - int32 port = 2; - - // An opaque but printable token given to the frontend for each pick. All - // frontend requests for that pick must include the token in its initial - // metadata. The token is used by the backend to verify the request and to - // allow the backend to report load to the gRPC LB system. The token is also - // used in client stats for reporting dropped calls. - string load_balance_token = 3; - - // Indicates whether this particular request should be dropped by the client. - // If the request is dropped, there will be a corresponding entry in - // ClientStats.calls_finished_with_drop. - bool drop = 4; - - reserved 5; -} diff --git a/vendor/google.golang.org/grpc/grpclb/grpc_lb_v1/service/service.pb.go b/vendor/google.golang.org/grpc/grpclb/grpc_lb_v1/service/service.pb.go deleted file mode 100644 index 3e4a97bfc437cad0f3c90f5392fdf7217a74efe0..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/grpclb/grpc_lb_v1/service/service.pb.go +++ /dev/null @@ -1,150 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: grpc_lb_v1/service/service.proto - -package service // import "google.golang.org/grpc/grpclb/grpc_lb_v1/service" - -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" -import messages "google.golang.org/grpc/grpclb/grpc_lb_v1/messages" - -import ( - context "golang.org/x/net/context" - grpc "google.golang.org/grpc" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 - -// LoadBalancerClient is the client API for LoadBalancer service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type LoadBalancerClient interface { - // Bidirectional rpc to get a list of servers. - BalanceLoad(ctx context.Context, opts ...grpc.CallOption) (LoadBalancer_BalanceLoadClient, error) -} - -type loadBalancerClient struct { - cc *grpc.ClientConn -} - -func NewLoadBalancerClient(cc *grpc.ClientConn) LoadBalancerClient { - return &loadBalancerClient{cc} -} - -func (c *loadBalancerClient) BalanceLoad(ctx context.Context, opts ...grpc.CallOption) (LoadBalancer_BalanceLoadClient, error) { - stream, err := c.cc.NewStream(ctx, &_LoadBalancer_serviceDesc.Streams[0], "/grpc.lb.v1.LoadBalancer/BalanceLoad", opts...) - if err != nil { - return nil, err - } - x := &loadBalancerBalanceLoadClient{stream} - return x, nil -} - -type LoadBalancer_BalanceLoadClient interface { - Send(*messages.LoadBalanceRequest) error - Recv() (*messages.LoadBalanceResponse, error) - grpc.ClientStream -} - -type loadBalancerBalanceLoadClient struct { - grpc.ClientStream -} - -func (x *loadBalancerBalanceLoadClient) Send(m *messages.LoadBalanceRequest) error { - return x.ClientStream.SendMsg(m) -} - -func (x *loadBalancerBalanceLoadClient) Recv() (*messages.LoadBalanceResponse, error) { - m := new(messages.LoadBalanceResponse) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -// LoadBalancerServer is the server API for LoadBalancer service. -type LoadBalancerServer interface { - // Bidirectional rpc to get a list of servers. - BalanceLoad(LoadBalancer_BalanceLoadServer) error -} - -func RegisterLoadBalancerServer(s *grpc.Server, srv LoadBalancerServer) { - s.RegisterService(&_LoadBalancer_serviceDesc, srv) -} - -func _LoadBalancer_BalanceLoad_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(LoadBalancerServer).BalanceLoad(&loadBalancerBalanceLoadServer{stream}) -} - -type LoadBalancer_BalanceLoadServer interface { - Send(*messages.LoadBalanceResponse) error - Recv() (*messages.LoadBalanceRequest, error) - grpc.ServerStream -} - -type loadBalancerBalanceLoadServer struct { - grpc.ServerStream -} - -func (x *loadBalancerBalanceLoadServer) Send(m *messages.LoadBalanceResponse) error { - return x.ServerStream.SendMsg(m) -} - -func (x *loadBalancerBalanceLoadServer) Recv() (*messages.LoadBalanceRequest, error) { - m := new(messages.LoadBalanceRequest) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -var _LoadBalancer_serviceDesc = grpc.ServiceDesc{ - ServiceName: "grpc.lb.v1.LoadBalancer", - HandlerType: (*LoadBalancerServer)(nil), - Methods: []grpc.MethodDesc{}, - Streams: []grpc.StreamDesc{ - { - StreamName: "BalanceLoad", - Handler: _LoadBalancer_BalanceLoad_Handler, - ServerStreams: true, - ClientStreams: true, - }, - }, - Metadata: "grpc_lb_v1/service/service.proto", -} - -func init() { - proto.RegisterFile("grpc_lb_v1/service/service.proto", fileDescriptor_service_8695ac2203226366) -} - -var fileDescriptor_service_8695ac2203226366 = []byte{ - // 166 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x8f, 0xbd, 0x0e, 0xc2, 0x40, - 0x08, 0x80, 0xd3, 0xc5, 0xe1, 0x74, 0xea, 0xd8, 0x41, 0x8d, 0x93, 0x13, 0xfd, 0xf1, 0x0d, 0x3a, - 0x3b, 0x75, 0x74, 0x69, 0xee, 0x2a, 0x21, 0x26, 0x58, 0xea, 0x51, 0xef, 0xf9, 0xcd, 0xd5, 0xbf, - 0x26, 0xc6, 0x05, 0xbe, 0xc0, 0x07, 0x01, 0xb3, 0x25, 0x3f, 0x74, 0x2d, 0xbb, 0x36, 0x94, 0xb9, - 0xa2, 0x0f, 0x97, 0x0e, 0xdf, 0x19, 0x06, 0x2f, 0xa3, 0xa4, 0x26, 0x1a, 0xc0, 0x0e, 0x42, 0x99, - 0xed, 0x66, 0xf6, 0x15, 0x55, 0x2d, 0xa1, 0x7e, 0xe0, 0xe9, 0x57, 0xce, 0xac, 0x8e, 0x62, 0xcf, - 0xb5, 0x65, 0xdb, 0x77, 0xe8, 0xd3, 0xc6, 0x2c, 0x5f, 0x1c, 0xcb, 0xe9, 0x1a, 0xbe, 0xfb, 0x60, - 0x26, 0x36, 0x78, 0xbb, 0xa3, 0x8e, 0xd9, 0xe6, 0x6f, 0x5f, 0x07, 0xe9, 0x15, 0xf7, 0x49, 0x91, - 0xd4, 0xd5, 0xa9, 0x20, 0x11, 0x62, 0x04, 0x12, 0xb6, 0x3d, 0x81, 0x78, 0xca, 0xe3, 0xdc, 0x14, - 0xd8, 0xe5, 0xbf, 0x5f, 0xb9, 0xc5, 0x74, 0xde, 0xe1, 0x11, 0x00, 0x00, 0xff, 0xff, 0x13, 0xde, - 0x84, 0x21, 0xf2, 0x00, 0x00, 0x00, -} diff --git a/vendor/google.golang.org/grpc/grpclb/grpc_lb_v1/service/service.proto b/vendor/google.golang.org/grpc/grpclb/grpc_lb_v1/service/service.proto deleted file mode 100644 index 6971fdba599bc8366e34ed9e0a75828f1a77023b..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/grpclb/grpc_lb_v1/service/service.proto +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2016 gRPC authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package grpc.lb.v1; -option go_package = "google.golang.org/grpc/grpclb/grpc_lb_v1/service"; - -import "grpc_lb_v1/messages/messages.proto"; - -service LoadBalancer { - // Bidirectional rpc to get a list of servers. - rpc BalanceLoad(stream LoadBalanceRequest) - returns (stream LoadBalanceResponse); -} diff --git a/vendor/google.golang.org/grpc/health/client.go b/vendor/google.golang.org/grpc/health/client.go new file mode 100644 index 0000000000000000000000000000000000000000..e15f04c229c4ca15add2f67a268b6aa585d50869 --- /dev/null +++ b/vendor/google.golang.org/grpc/health/client.go @@ -0,0 +1,107 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package health + +import ( + "context" + "fmt" + "io" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + healthpb "google.golang.org/grpc/health/grpc_health_v1" + "google.golang.org/grpc/internal" + "google.golang.org/grpc/internal/backoff" + "google.golang.org/grpc/status" +) + +const maxDelay = 120 * time.Second + +var backoffStrategy = backoff.Exponential{MaxDelay: maxDelay} +var backoffFunc = func(ctx context.Context, retries int) bool { + d := backoffStrategy.Backoff(retries) + timer := time.NewTimer(d) + select { + case <-timer.C: + return true + case <-ctx.Done(): + timer.Stop() + return false + } +} + +func init() { + internal.HealthCheckFunc = clientHealthCheck +} + +func clientHealthCheck(ctx context.Context, newStream func() (interface{}, error), reportHealth func(bool), service string) error { + tryCnt := 0 + +retryConnection: + for { + // Backs off if the connection has failed in some way without receiving a message in the previous retry. + if tryCnt > 0 && !backoffFunc(ctx, tryCnt-1) { + return nil + } + tryCnt++ + + if ctx.Err() != nil { + return nil + } + rawS, err := newStream() + if err != nil { + continue retryConnection + } + + s, ok := rawS.(grpc.ClientStream) + // Ideally, this should never happen. But if it happens, the server is marked as healthy for LBing purposes. + if !ok { + reportHealth(true) + return fmt.Errorf("newStream returned %v (type %T); want grpc.ClientStream", rawS, rawS) + } + + if err = s.SendMsg(&healthpb.HealthCheckRequest{Service: service}); err != nil && err != io.EOF { + // Stream should have been closed, so we can safely continue to create a new stream. + continue retryConnection + } + s.CloseSend() + + resp := new(healthpb.HealthCheckResponse) + for { + err = s.RecvMsg(resp) + + // Reports healthy for the LBing purposes if health check is not implemented in the server. + if status.Code(err) == codes.Unimplemented { + reportHealth(true) + return err + } + + // Reports unhealthy if server's Watch method gives an error other than UNIMPLEMENTED. + if err != nil { + reportHealth(false) + continue retryConnection + } + + // As a message has been received, removes the need for backoff for the next retry by reseting the try count. + tryCnt = 0 + reportHealth(resp.Status == healthpb.HealthCheckResponse_SERVING) + } + } +} diff --git a/vendor/google.golang.org/grpc/health/client_test.go b/vendor/google.golang.org/grpc/health/client_test.go new file mode 100644 index 0000000000000000000000000000000000000000..894b66ba7fc35bbbefdbfd56a8b8b07430a1f653 --- /dev/null +++ b/vendor/google.golang.org/grpc/health/client_test.go @@ -0,0 +1,57 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package health + +import ( + "context" + "errors" + "reflect" + "testing" + "time" +) + +func TestClientHealthCheckBackoff(t *testing.T) { + const maxRetries = 5 + + var want []time.Duration + for i := 0; i < maxRetries; i++ { + want = append(want, time.Duration(i+1)*time.Second) + } + + var got []time.Duration + newStream := func() (interface{}, error) { + if len(got) < maxRetries { + return nil, errors.New("backoff") + } + return nil, nil + } + + oldBackoffFunc := backoffFunc + backoffFunc = func(ctx context.Context, retries int) bool { + got = append(got, time.Duration(retries+1)*time.Second) + return true + } + defer func() { backoffFunc = oldBackoffFunc }() + + clientHealthCheck(context.Background(), newStream, func(_ bool) {}, "test") + + if !reflect.DeepEqual(got, want) { + t.Fatalf("Backoff durations for %v retries are %v. (expected: %v)", maxRetries, got, want) + } +} diff --git a/vendor/google.golang.org/grpc/health/grpc_health_v1/health.pb.go b/vendor/google.golang.org/grpc/health/grpc_health_v1/health.pb.go index a1fda2801b8fff349d12f41d0363fe11ad9241bc..c2f2c7729d056f48e22d84bb5deff2418c74fac7 100644 --- a/vendor/google.golang.org/grpc/health/grpc_health_v1/health.pb.go +++ b/vendor/google.golang.org/grpc/health/grpc_health_v1/health.pb.go @@ -26,27 +26,30 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package type HealthCheckResponse_ServingStatus int32 const ( - HealthCheckResponse_UNKNOWN HealthCheckResponse_ServingStatus = 0 - HealthCheckResponse_SERVING HealthCheckResponse_ServingStatus = 1 - HealthCheckResponse_NOT_SERVING HealthCheckResponse_ServingStatus = 2 + HealthCheckResponse_UNKNOWN HealthCheckResponse_ServingStatus = 0 + HealthCheckResponse_SERVING HealthCheckResponse_ServingStatus = 1 + HealthCheckResponse_NOT_SERVING HealthCheckResponse_ServingStatus = 2 + HealthCheckResponse_SERVICE_UNKNOWN HealthCheckResponse_ServingStatus = 3 ) var HealthCheckResponse_ServingStatus_name = map[int32]string{ 0: "UNKNOWN", 1: "SERVING", 2: "NOT_SERVING", + 3: "SERVICE_UNKNOWN", } var HealthCheckResponse_ServingStatus_value = map[string]int32{ - "UNKNOWN": 0, - "SERVING": 1, - "NOT_SERVING": 2, + "UNKNOWN": 0, + "SERVING": 1, + "NOT_SERVING": 2, + "SERVICE_UNKNOWN": 3, } func (x HealthCheckResponse_ServingStatus) String() string { return proto.EnumName(HealthCheckResponse_ServingStatus_name, int32(x)) } func (HealthCheckResponse_ServingStatus) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_health_85731b6c49265086, []int{1, 0} + return fileDescriptor_health_6b1a06aa67f91efd, []int{1, 0} } type HealthCheckRequest struct { @@ -60,7 +63,7 @@ func (m *HealthCheckRequest) Reset() { *m = HealthCheckRequest{} } func (m *HealthCheckRequest) String() string { return proto.CompactTextString(m) } func (*HealthCheckRequest) ProtoMessage() {} func (*HealthCheckRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_health_85731b6c49265086, []int{0} + return fileDescriptor_health_6b1a06aa67f91efd, []int{0} } func (m *HealthCheckRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_HealthCheckRequest.Unmarshal(m, b) @@ -98,7 +101,7 @@ func (m *HealthCheckResponse) Reset() { *m = HealthCheckResponse{} } func (m *HealthCheckResponse) String() string { return proto.CompactTextString(m) } func (*HealthCheckResponse) ProtoMessage() {} func (*HealthCheckResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_health_85731b6c49265086, []int{1} + return fileDescriptor_health_6b1a06aa67f91efd, []int{1} } func (m *HealthCheckResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_HealthCheckResponse.Unmarshal(m, b) @@ -143,7 +146,25 @@ const _ = grpc.SupportPackageIsVersion4 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type HealthClient interface { + // If the requested service is unknown, the call will fail with status + // NOT_FOUND. Check(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) + // Performs a watch for the serving status of the requested service. + // The server will immediately send back a message indicating the current + // serving status. It will then subsequently send a new message whenever + // the service's serving status changes. + // + // If the requested service is unknown when the call is received, the + // server will send a message setting the serving status to + // SERVICE_UNKNOWN but will *not* terminate the call. If at some + // future point, the serving status of the service becomes known, the + // server will send a new message with the service's serving status. + // + // If the call terminates with status UNIMPLEMENTED, then clients + // should assume this method is not supported and should not retry the + // call. If the call terminates with any other status (including OK), + // clients should retry the call with appropriate exponential backoff. + Watch(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (Health_WatchClient, error) } type healthClient struct { @@ -163,9 +184,59 @@ func (c *healthClient) Check(ctx context.Context, in *HealthCheckRequest, opts . return out, nil } +func (c *healthClient) Watch(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (Health_WatchClient, error) { + stream, err := c.cc.NewStream(ctx, &_Health_serviceDesc.Streams[0], "/grpc.health.v1.Health/Watch", opts...) + if err != nil { + return nil, err + } + x := &healthWatchClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type Health_WatchClient interface { + Recv() (*HealthCheckResponse, error) + grpc.ClientStream +} + +type healthWatchClient struct { + grpc.ClientStream +} + +func (x *healthWatchClient) Recv() (*HealthCheckResponse, error) { + m := new(HealthCheckResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + // HealthServer is the server API for Health service. type HealthServer interface { + // If the requested service is unknown, the call will fail with status + // NOT_FOUND. Check(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error) + // Performs a watch for the serving status of the requested service. + // The server will immediately send back a message indicating the current + // serving status. It will then subsequently send a new message whenever + // the service's serving status changes. + // + // If the requested service is unknown when the call is received, the + // server will send a message setting the serving status to + // SERVICE_UNKNOWN but will *not* terminate the call. If at some + // future point, the serving status of the service becomes known, the + // server will send a new message with the service's serving status. + // + // If the call terminates with status UNIMPLEMENTED, then clients + // should assume this method is not supported and should not retry the + // call. If the call terminates with any other status (including OK), + // clients should retry the call with appropriate exponential backoff. + Watch(*HealthCheckRequest, Health_WatchServer) error } func RegisterHealthServer(s *grpc.Server, srv HealthServer) { @@ -190,6 +261,27 @@ func _Health_Check_Handler(srv interface{}, ctx context.Context, dec func(interf return interceptor(ctx, in, info, handler) } +func _Health_Watch_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(HealthCheckRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(HealthServer).Watch(m, &healthWatchServer{stream}) +} + +type Health_WatchServer interface { + Send(*HealthCheckResponse) error + grpc.ServerStream +} + +type healthWatchServer struct { + grpc.ServerStream +} + +func (x *healthWatchServer) Send(m *HealthCheckResponse) error { + return x.ServerStream.SendMsg(m) +} + var _Health_serviceDesc = grpc.ServiceDesc{ ServiceName: "grpc.health.v1.Health", HandlerType: (*HealthServer)(nil), @@ -199,29 +291,37 @@ var _Health_serviceDesc = grpc.ServiceDesc{ Handler: _Health_Check_Handler, }, }, - Streams: []grpc.StreamDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "Watch", + Handler: _Health_Watch_Handler, + ServerStreams: true, + }, + }, Metadata: "grpc/health/v1/health.proto", } -func init() { proto.RegisterFile("grpc/health/v1/health.proto", fileDescriptor_health_85731b6c49265086) } +func init() { proto.RegisterFile("grpc/health/v1/health.proto", fileDescriptor_health_6b1a06aa67f91efd) } -var fileDescriptor_health_85731b6c49265086 = []byte{ - // 271 bytes of a gzipped FileDescriptorProto +var fileDescriptor_health_6b1a06aa67f91efd = []byte{ + // 297 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4e, 0x2f, 0x2a, 0x48, 0xd6, 0xcf, 0x48, 0x4d, 0xcc, 0x29, 0xc9, 0xd0, 0x2f, 0x33, 0x84, 0xb2, 0xf4, 0x0a, 0x8a, 0xf2, 0x4b, 0xf2, 0x85, 0xf8, 0x40, 0x92, 0x7a, 0x50, 0xa1, 0x32, 0x43, 0x25, 0x3d, 0x2e, 0x21, 0x0f, 0x30, 0xc7, 0x39, 0x23, 0x35, 0x39, 0x3b, 0x28, 0xb5, 0xb0, 0x34, 0xb5, 0xb8, 0x44, 0x48, 0x82, 0x8b, 0xbd, 0x38, 0xb5, 0xa8, 0x2c, 0x33, 0x39, 0x55, 0x82, 0x51, 0x81, 0x51, 0x83, 0x33, 0x08, - 0xc6, 0x55, 0x9a, 0xc3, 0xc8, 0x25, 0x8c, 0xa2, 0xa1, 0xb8, 0x20, 0x3f, 0xaf, 0x38, 0x55, 0xc8, + 0xc6, 0x55, 0xda, 0xc8, 0xc8, 0x25, 0x8c, 0xa2, 0xa1, 0xb8, 0x20, 0x3f, 0xaf, 0x38, 0x55, 0xc8, 0x93, 0x8b, 0xad, 0xb8, 0x24, 0xb1, 0xa4, 0xb4, 0x18, 0xac, 0x81, 0xcf, 0xc8, 0x50, 0x0f, 0xd5, 0x22, 0x3d, 0x2c, 0x9a, 0xf4, 0x82, 0x41, 0x86, 0xe6, 0xa5, 0x07, 0x83, 0x35, 0x06, 0x41, 0x0d, - 0x50, 0xb2, 0xe2, 0xe2, 0x45, 0x91, 0x10, 0xe2, 0xe6, 0x62, 0x0f, 0xf5, 0xf3, 0xf6, 0xf3, 0x0f, + 0x50, 0xf2, 0xe7, 0xe2, 0x45, 0x91, 0x10, 0xe2, 0xe6, 0x62, 0x0f, 0xf5, 0xf3, 0xf6, 0xf3, 0x0f, 0xf7, 0x13, 0x60, 0x00, 0x71, 0x82, 0x5d, 0x83, 0xc2, 0x3c, 0xfd, 0xdc, 0x05, 0x18, 0x85, 0xf8, - 0xb9, 0xb8, 0xfd, 0xfc, 0x43, 0xe2, 0x61, 0x02, 0x4c, 0x46, 0x51, 0x5c, 0x6c, 0x10, 0x8b, 0x84, - 0x02, 0xb8, 0x58, 0xc1, 0x96, 0x09, 0x29, 0xe1, 0x75, 0x09, 0xd8, 0xbf, 0x52, 0xca, 0x44, 0xb8, - 0xd6, 0x29, 0x91, 0x4b, 0x30, 0x33, 0x1f, 0x4d, 0xa1, 0x13, 0x37, 0x44, 0x65, 0x00, 0x28, 0x70, - 0x03, 0x18, 0xa3, 0x74, 0xd2, 0xf3, 0xf3, 0xd3, 0x73, 0x52, 0xf5, 0xd2, 0xf3, 0x73, 0x12, 0xf3, - 0xd2, 0xf5, 0xf2, 0x8b, 0xd2, 0xf5, 0x91, 0x63, 0x03, 0xc4, 0x8e, 0x87, 0xb0, 0xe3, 0xcb, 0x0c, - 0x57, 0x31, 0xf1, 0xb9, 0x83, 0x4c, 0x83, 0x18, 0xa1, 0x17, 0x66, 0x98, 0xc4, 0x06, 0x8e, 0x24, - 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xec, 0x66, 0x81, 0xcb, 0xc3, 0x01, 0x00, 0x00, + 0xb9, 0xb8, 0xfd, 0xfc, 0x43, 0xe2, 0x61, 0x02, 0x4c, 0x42, 0xc2, 0x5c, 0xfc, 0x60, 0x8e, 0xb3, + 0x6b, 0x3c, 0x4c, 0x0b, 0xb3, 0xd1, 0x3a, 0x46, 0x2e, 0x36, 0x88, 0xf5, 0x42, 0x01, 0x5c, 0xac, + 0x60, 0x27, 0x08, 0x29, 0xe1, 0x75, 0x1f, 0x38, 0x14, 0xa4, 0x94, 0x89, 0xf0, 0x83, 0x50, 0x10, + 0x17, 0x6b, 0x78, 0x62, 0x49, 0x72, 0x06, 0xd5, 0x4c, 0x34, 0x60, 0x74, 0x4a, 0xe4, 0x12, 0xcc, + 0xcc, 0x47, 0x53, 0xea, 0xc4, 0x0d, 0x51, 0x1b, 0x00, 0x8a, 0xc6, 0x00, 0xc6, 0x28, 0x9d, 0xf4, + 0xfc, 0xfc, 0xf4, 0x9c, 0x54, 0xbd, 0xf4, 0xfc, 0x9c, 0xc4, 0xbc, 0x74, 0xbd, 0xfc, 0xa2, 0x74, + 0x7d, 0xe4, 0x78, 0x07, 0xb1, 0xe3, 0x21, 0xec, 0xf8, 0x32, 0xc3, 0x55, 0x4c, 0x7c, 0xee, 0x20, + 0xd3, 0x20, 0x46, 0xe8, 0x85, 0x19, 0x26, 0xb1, 0x81, 0x93, 0x83, 0x31, 0x20, 0x00, 0x00, 0xff, + 0xff, 0x12, 0x7d, 0x96, 0xcb, 0x2d, 0x02, 0x00, 0x00, } diff --git a/vendor/google.golang.org/grpc/health/health.go b/vendor/google.golang.org/grpc/health/health.go deleted file mode 100644 index c2588867e5a1cb6d1873a73bb6c49be7fa0bc168..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/health/health.go +++ /dev/null @@ -1,72 +0,0 @@ -/* - * - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -//go:generate ./regenerate.sh - -// Package health provides some utility functions to health-check a server. The implementation -// is based on protobuf. Users need to write their own implementations if other IDLs are used. -package health - -import ( - "sync" - - "golang.org/x/net/context" - "google.golang.org/grpc/codes" - healthpb "google.golang.org/grpc/health/grpc_health_v1" - "google.golang.org/grpc/status" -) - -// Server implements `service Health`. -type Server struct { - mu sync.Mutex - // statusMap stores the serving status of the services this Server monitors. - statusMap map[string]healthpb.HealthCheckResponse_ServingStatus -} - -// NewServer returns a new Server. -func NewServer() *Server { - return &Server{ - statusMap: make(map[string]healthpb.HealthCheckResponse_ServingStatus), - } -} - -// Check implements `service Health`. -func (s *Server) Check(ctx context.Context, in *healthpb.HealthCheckRequest) (*healthpb.HealthCheckResponse, error) { - s.mu.Lock() - defer s.mu.Unlock() - if in.Service == "" { - // check the server overall health status. - return &healthpb.HealthCheckResponse{ - Status: healthpb.HealthCheckResponse_SERVING, - }, nil - } - if status, ok := s.statusMap[in.Service]; ok { - return &healthpb.HealthCheckResponse{ - Status: status, - }, nil - } - return nil, status.Error(codes.NotFound, "unknown service") -} - -// SetServingStatus is called when need to reset the serving status of a service -// or insert a new service entry into the statusMap. -func (s *Server) SetServingStatus(service string, status healthpb.HealthCheckResponse_ServingStatus) { - s.mu.Lock() - s.statusMap[service] = status - s.mu.Unlock() -} diff --git a/vendor/google.golang.org/grpc/health/server.go b/vendor/google.golang.org/grpc/health/server.go new file mode 100644 index 0000000000000000000000000000000000000000..c86e4998897d1256e1bdadb716275a52f925d8b9 --- /dev/null +++ b/vendor/google.golang.org/grpc/health/server.go @@ -0,0 +1,125 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +//go:generate ./regenerate.sh + +// Package health provides a service that exposes server's health and it must be +// imported to enable support for client-side health checks. +package health + +import ( + "context" + "sync" + + "google.golang.org/grpc/codes" + healthgrpc "google.golang.org/grpc/health/grpc_health_v1" + healthpb "google.golang.org/grpc/health/grpc_health_v1" + "google.golang.org/grpc/status" +) + +// Server implements `service Health`. +type Server struct { + mu sync.Mutex + // statusMap stores the serving status of the services this Server monitors. + statusMap map[string]healthpb.HealthCheckResponse_ServingStatus + updates map[string]map[healthgrpc.Health_WatchServer]chan healthpb.HealthCheckResponse_ServingStatus +} + +// NewServer returns a new Server. +func NewServer() *Server { + return &Server{ + statusMap: map[string]healthpb.HealthCheckResponse_ServingStatus{"": healthpb.HealthCheckResponse_SERVING}, + updates: make(map[string]map[healthgrpc.Health_WatchServer]chan healthpb.HealthCheckResponse_ServingStatus), + } +} + +// Check implements `service Health`. +func (s *Server) Check(ctx context.Context, in *healthpb.HealthCheckRequest) (*healthpb.HealthCheckResponse, error) { + s.mu.Lock() + defer s.mu.Unlock() + if servingStatus, ok := s.statusMap[in.Service]; ok { + return &healthpb.HealthCheckResponse{ + Status: servingStatus, + }, nil + } + return nil, status.Error(codes.NotFound, "unknown service") +} + +// Watch implements `service Health`. +func (s *Server) Watch(in *healthpb.HealthCheckRequest, stream healthgrpc.Health_WatchServer) error { + service := in.Service + // update channel is used for getting service status updates. + update := make(chan healthpb.HealthCheckResponse_ServingStatus, 1) + s.mu.Lock() + // Puts the initial status to the channel. + if servingStatus, ok := s.statusMap[service]; ok { + update <- servingStatus + } else { + update <- healthpb.HealthCheckResponse_SERVICE_UNKNOWN + } + + // Registers the update channel to the correct place in the updates map. + if _, ok := s.updates[service]; !ok { + s.updates[service] = make(map[healthgrpc.Health_WatchServer]chan healthpb.HealthCheckResponse_ServingStatus) + } + s.updates[service][stream] = update + defer func() { + s.mu.Lock() + delete(s.updates[service], stream) + s.mu.Unlock() + }() + s.mu.Unlock() + + var lastSentStatus healthpb.HealthCheckResponse_ServingStatus = -1 + for { + select { + // Status updated. Sends the up-to-date status to the client. + case servingStatus := <-update: + if lastSentStatus == servingStatus { + continue + } + lastSentStatus = servingStatus + err := stream.Send(&healthpb.HealthCheckResponse{Status: servingStatus}) + if err != nil { + return status.Error(codes.Canceled, "Stream has ended.") + } + // Context done. Removes the update channel from the updates map. + case <-stream.Context().Done(): + return status.Error(codes.Canceled, "Stream has ended.") + } + } +} + +// SetServingStatus is called when need to reset the serving status of a service +// or insert a new service entry into the statusMap. +func (s *Server) SetServingStatus(service string, servingStatus healthpb.HealthCheckResponse_ServingStatus) { + s.mu.Lock() + defer s.mu.Unlock() + + s.statusMap[service] = servingStatus + for _, update := range s.updates[service] { + // Clears previous updates, that are not sent to the client, from the channel. + // This can happen if the client is not reading and the server gets flow control limited. + select { + case <-update: + default: + } + // Puts the most recent update to the channel. + update <- servingStatus + } +} diff --git a/vendor/google.golang.org/grpc/health/server_test.go b/vendor/google.golang.org/grpc/health/server_test.go new file mode 100644 index 0000000000000000000000000000000000000000..c07dabe0e3ad1e41cd2ee316916629f0ef0cf4ca --- /dev/null +++ b/vendor/google.golang.org/grpc/health/server_test.go @@ -0,0 +1,34 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package health_test + +import ( + "testing" + + "google.golang.org/grpc" + "google.golang.org/grpc/health" + healthgrpc "google.golang.org/grpc/health/grpc_health_v1" +) + +// Make sure the service implementation complies with the proto definition. +func TestRegister(t *testing.T) { + s := grpc.NewServer() + healthgrpc.RegisterHealthServer(s, health.NewServer()) + s.Stop() +} diff --git a/vendor/google.golang.org/grpc/install_gae.sh b/vendor/google.golang.org/grpc/install_gae.sh new file mode 100755 index 0000000000000000000000000000000000000000..7c7bcada5044296734fadc48cb254ab5b9ff33db --- /dev/null +++ b/vendor/google.golang.org/grpc/install_gae.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +TMP=$(mktemp -d /tmp/sdk.XXX) \ +&& curl -o $TMP.zip "https://storage.googleapis.com/appengine-sdks/featured/go_appengine_sdk_linux_amd64-1.9.68.zip" \ +&& unzip -q $TMP.zip -d $TMP \ +&& export PATH="$PATH:$TMP/go_appengine" diff --git a/vendor/google.golang.org/grpc/interceptor.go b/vendor/google.golang.org/grpc/interceptor.go index 1f6ef678035b435a001c9a93412c839843d341aa..8b7350022ad735344d903ef324113d47df5ae4b8 100644 --- a/vendor/google.golang.org/grpc/interceptor.go +++ b/vendor/google.golang.org/grpc/interceptor.go @@ -19,7 +19,7 @@ package grpc import ( - "golang.org/x/net/context" + "context" ) // UnaryInvoker is called by UnaryClientInterceptor to complete RPCs. diff --git a/vendor/google.golang.org/grpc/internal/binarylog/binarylog.go b/vendor/google.golang.org/grpc/internal/binarylog/binarylog.go new file mode 100644 index 0000000000000000000000000000000000000000..fee6aecd08f60c0aa8b5b8d2e746a294e886d54a --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/binarylog/binarylog.go @@ -0,0 +1,167 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package binarylog implementation binary logging as defined in +// https://github.com/grpc/proposal/blob/master/A16-binary-logging.md. +package binarylog + +import ( + "fmt" + "os" + + "google.golang.org/grpc/grpclog" +) + +// Logger is the global binary logger. It can be used to get binary logger for +// each method. +type Logger interface { + getMethodLogger(methodName string) *MethodLogger +} + +// binLogger is the global binary logger for the binary. One of this should be +// built at init time from the configuration (environment varialbe or flags). +// +// It is used to get a methodLogger for each individual method. +var binLogger Logger + +// SetLogger sets the binarg logger. +// +// Only call this at init time. +func SetLogger(l Logger) { + binLogger = l +} + +// GetMethodLogger returns the methodLogger for the given methodName. +// +// methodName should be in the format of "/service/method". +// +// Each methodLogger returned by this method is a new instance. This is to +// generate sequence id within the call. +func GetMethodLogger(methodName string) *MethodLogger { + if binLogger == nil { + return nil + } + return binLogger.getMethodLogger(methodName) +} + +func init() { + const envStr = "GRPC_BINARY_LOG_FILTER" + configStr := os.Getenv(envStr) + binLogger = NewLoggerFromConfigString(configStr) +} + +type methodLoggerConfig struct { + // Max length of header and message. + hdr, msg uint64 +} + +type logger struct { + all *methodLoggerConfig + services map[string]*methodLoggerConfig + methods map[string]*methodLoggerConfig + + blacklist map[string]struct{} +} + +// newEmptyLogger creates an empty logger. The map fields need to be filled in +// using the set* functions. +func newEmptyLogger() *logger { + return &logger{} +} + +// Set method logger for "*". +func (l *logger) setDefaultMethodLogger(ml *methodLoggerConfig) error { + if l.all != nil { + return fmt.Errorf("conflicting global rules found") + } + l.all = ml + return nil +} + +// Set method logger for "service/*". +// +// New methodLogger with same service overrides the old one. +func (l *logger) setServiceMethodLogger(service string, ml *methodLoggerConfig) error { + if _, ok := l.services[service]; ok { + return fmt.Errorf("conflicting rules for service %v found", service) + } + if l.services == nil { + l.services = make(map[string]*methodLoggerConfig) + } + l.services[service] = ml + return nil +} + +// Set method logger for "service/method". +// +// New methodLogger with same method overrides the old one. +func (l *logger) setMethodMethodLogger(method string, ml *methodLoggerConfig) error { + if _, ok := l.blacklist[method]; ok { + return fmt.Errorf("conflicting rules for method %v found", method) + } + if _, ok := l.methods[method]; ok { + return fmt.Errorf("conflicting rules for method %v found", method) + } + if l.methods == nil { + l.methods = make(map[string]*methodLoggerConfig) + } + l.methods[method] = ml + return nil +} + +// Set blacklist method for "-service/method". +func (l *logger) setBlacklist(method string) error { + if _, ok := l.blacklist[method]; ok { + return fmt.Errorf("conflicting rules for method %v found", method) + } + if _, ok := l.methods[method]; ok { + return fmt.Errorf("conflicting rules for method %v found", method) + } + if l.blacklist == nil { + l.blacklist = make(map[string]struct{}) + } + l.blacklist[method] = struct{}{} + return nil +} + +// getMethodLogger returns the methodLogger for the given methodName. +// +// methodName should be in the format of "/service/method". +// +// Each methodLogger returned by this method is a new instance. This is to +// generate sequence id within the call. +func (l *logger) getMethodLogger(methodName string) *MethodLogger { + s, m, err := parseMethodName(methodName) + if err != nil { + grpclog.Infof("binarylogging: failed to parse %q: %v", methodName, err) + return nil + } + if ml, ok := l.methods[s+"/"+m]; ok { + return newMethodLogger(ml.hdr, ml.msg) + } + if _, ok := l.blacklist[s+"/"+m]; ok { + return nil + } + if ml, ok := l.services[s]; ok { + return newMethodLogger(ml.hdr, ml.msg) + } + if l.all == nil { + return nil + } + return newMethodLogger(l.all.hdr, l.all.msg) +} diff --git a/vendor/google.golang.org/grpc/internal/binarylog/binarylog_end2end_test.go b/vendor/google.golang.org/grpc/internal/binarylog/binarylog_end2end_test.go new file mode 100644 index 0000000000000000000000000000000000000000..6d25f1be62764d36820b1e1116692e7f025a81c7 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/binarylog/binarylog_end2end_test.go @@ -0,0 +1,1044 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package binarylog_test + +import ( + "context" + "fmt" + "io" + "net" + "sort" + "sync" + "testing" + "time" + + "github.com/golang/protobuf/proto" + + "google.golang.org/grpc" + pb "google.golang.org/grpc/binarylog/grpc_binarylog_v1" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/internal/binarylog" + "google.golang.org/grpc/metadata" + testpb "google.golang.org/grpc/stats/grpc_testing" + "google.golang.org/grpc/status" +) + +func init() { + // Setting environment variable in tests doesn't work because of the init + // orders. Set the loggers directly here. + binarylog.SetLogger(binarylog.AllLogger) + binarylog.SetDefaultSink(testSink) +} + +var testSink = &testBinLogSink{} + +type testBinLogSink struct { + mu sync.Mutex + buf []*pb.GrpcLogEntry +} + +func (s *testBinLogSink) Write(e *pb.GrpcLogEntry) error { + s.mu.Lock() + s.buf = append(s.buf, e) + s.mu.Unlock() + return nil +} + +func (s *testBinLogSink) Close() error { return nil } + +// Returns all client entris if client is true, otherwise return all server +// entries. +func (s *testBinLogSink) logEntries(client bool) []*pb.GrpcLogEntry { + logger := pb.GrpcLogEntry_LOGGER_SERVER + if client { + logger = pb.GrpcLogEntry_LOGGER_CLIENT + } + var ret []*pb.GrpcLogEntry + s.mu.Lock() + for _, e := range s.buf { + if e.Logger == logger { + ret = append(ret, e) + } + } + s.mu.Unlock() + return ret +} + +func (s *testBinLogSink) clear() { + s.mu.Lock() + s.buf = nil + s.mu.Unlock() +} + +var ( + // For headers: + testMetadata = metadata.MD{ + "key1": []string{"value1"}, + "key2": []string{"value2"}, + } + // For trailers: + testTrailerMetadata = metadata.MD{ + "tkey1": []string{"trailerValue1"}, + "tkey2": []string{"trailerValue2"}, + } + // The id for which the service handler should return error. + errorID int32 = 32202 + + globalRPCID uint64 // RPC id starts with 1, but we do ++ at the beginning of each test. +) + +type testServer struct { + te *test +} + +func (s *testServer) UnaryCall(ctx context.Context, in *testpb.SimpleRequest) (*testpb.SimpleResponse, error) { + md, ok := metadata.FromIncomingContext(ctx) + if ok { + if err := grpc.SendHeader(ctx, md); err != nil { + return nil, status.Errorf(status.Code(err), "grpc.SendHeader(_, %v) = %v, want ", md, err) + } + if err := grpc.SetTrailer(ctx, testTrailerMetadata); err != nil { + return nil, status.Errorf(status.Code(err), "grpc.SetTrailer(_, %v) = %v, want ", testTrailerMetadata, err) + } + } + + if in.Id == errorID { + return nil, fmt.Errorf("got error id: %v", in.Id) + } + + return &testpb.SimpleResponse{Id: in.Id}, nil +} + +func (s *testServer) FullDuplexCall(stream testpb.TestService_FullDuplexCallServer) error { + md, ok := metadata.FromIncomingContext(stream.Context()) + if ok { + if err := stream.SendHeader(md); err != nil { + return status.Errorf(status.Code(err), "stream.SendHeader(%v) = %v, want %v", md, err, nil) + } + stream.SetTrailer(testTrailerMetadata) + } + for { + in, err := stream.Recv() + if err == io.EOF { + // read done. + return nil + } + if err != nil { + return err + } + + if in.Id == errorID { + return fmt.Errorf("got error id: %v", in.Id) + } + + if err := stream.Send(&testpb.SimpleResponse{Id: in.Id}); err != nil { + return err + } + } +} + +func (s *testServer) ClientStreamCall(stream testpb.TestService_ClientStreamCallServer) error { + md, ok := metadata.FromIncomingContext(stream.Context()) + if ok { + if err := stream.SendHeader(md); err != nil { + return status.Errorf(status.Code(err), "stream.SendHeader(%v) = %v, want %v", md, err, nil) + } + stream.SetTrailer(testTrailerMetadata) + } + for { + in, err := stream.Recv() + if err == io.EOF { + // read done. + return stream.SendAndClose(&testpb.SimpleResponse{Id: int32(0)}) + } + if err != nil { + return err + } + + if in.Id == errorID { + return fmt.Errorf("got error id: %v", in.Id) + } + } +} + +func (s *testServer) ServerStreamCall(in *testpb.SimpleRequest, stream testpb.TestService_ServerStreamCallServer) error { + md, ok := metadata.FromIncomingContext(stream.Context()) + if ok { + if err := stream.SendHeader(md); err != nil { + return status.Errorf(status.Code(err), "stream.SendHeader(%v) = %v, want %v", md, err, nil) + } + stream.SetTrailer(testTrailerMetadata) + } + + if in.Id == errorID { + return fmt.Errorf("got error id: %v", in.Id) + } + + for i := 0; i < 5; i++ { + if err := stream.Send(&testpb.SimpleResponse{Id: in.Id}); err != nil { + return err + } + } + return nil +} + +// test is an end-to-end test. It should be created with the newTest +// func, modified as needed, and then started with its startServer method. +// It should be cleaned up with the tearDown method. +type test struct { + t *testing.T + + testServer testpb.TestServiceServer // nil means none + // srv and srvAddr are set once startServer is called. + srv *grpc.Server + srvAddr string // Server IP without port. + srvIP net.IP + srvPort int + + cc *grpc.ClientConn // nil until requested via clientConn + + // Fields for client address. Set by the service handler. + clientAddrMu sync.Mutex + clientIP net.IP + clientPort int +} + +func (te *test) tearDown() { + if te.cc != nil { + te.cc.Close() + te.cc = nil + } + te.srv.Stop() +} + +type testConfig struct { +} + +// newTest returns a new test using the provided testing.T and +// environment. It is returned with default values. Tests should +// modify it before calling its startServer and clientConn methods. +func newTest(t *testing.T, tc *testConfig) *test { + te := &test{ + t: t, + } + return te +} + +type listenerWrapper struct { + net.Listener + te *test +} + +func (lw *listenerWrapper) Accept() (net.Conn, error) { + conn, err := lw.Listener.Accept() + if err != nil { + return nil, err + } + lw.te.clientAddrMu.Lock() + lw.te.clientIP = conn.RemoteAddr().(*net.TCPAddr).IP + lw.te.clientPort = conn.RemoteAddr().(*net.TCPAddr).Port + lw.te.clientAddrMu.Unlock() + return conn, nil +} + +// startServer starts a gRPC server listening. Callers should defer a +// call to te.tearDown to clean up. +func (te *test) startServer(ts testpb.TestServiceServer) { + te.testServer = ts + lis, err := net.Listen("tcp", "localhost:0") + + lis = &listenerWrapper{ + Listener: lis, + te: te, + } + + if err != nil { + te.t.Fatalf("Failed to listen: %v", err) + } + var opts []grpc.ServerOption + s := grpc.NewServer(opts...) + te.srv = s + if te.testServer != nil { + testpb.RegisterTestServiceServer(s, te.testServer) + } + + go s.Serve(lis) + te.srvAddr = lis.Addr().String() + te.srvIP = lis.Addr().(*net.TCPAddr).IP + te.srvPort = lis.Addr().(*net.TCPAddr).Port +} + +func (te *test) clientConn() *grpc.ClientConn { + if te.cc != nil { + return te.cc + } + opts := []grpc.DialOption{grpc.WithInsecure(), grpc.WithBlock()} + + var err error + te.cc, err = grpc.Dial(te.srvAddr, opts...) + if err != nil { + te.t.Fatalf("Dial(%q) = %v", te.srvAddr, err) + } + return te.cc +} + +type rpcType int + +const ( + unaryRPC rpcType = iota + clientStreamRPC + serverStreamRPC + fullDuplexStreamRPC + cancelRPC +) + +type rpcConfig struct { + count int // Number of requests and responses for streaming RPCs. + success bool // Whether the RPC should succeed or return error. + callType rpcType // Type of RPC. +} + +func (te *test) doUnaryCall(c *rpcConfig) (*testpb.SimpleRequest, *testpb.SimpleResponse, error) { + var ( + resp *testpb.SimpleResponse + req *testpb.SimpleRequest + err error + ) + tc := testpb.NewTestServiceClient(te.clientConn()) + if c.success { + req = &testpb.SimpleRequest{Id: errorID + 1} + } else { + req = &testpb.SimpleRequest{Id: errorID} + } + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + ctx = metadata.NewOutgoingContext(ctx, testMetadata) + + resp, err = tc.UnaryCall(ctx, req) + return req, resp, err +} + +func (te *test) doFullDuplexCallRoundtrip(c *rpcConfig) ([]*testpb.SimpleRequest, []*testpb.SimpleResponse, error) { + var ( + reqs []*testpb.SimpleRequest + resps []*testpb.SimpleResponse + err error + ) + tc := testpb.NewTestServiceClient(te.clientConn()) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + ctx = metadata.NewOutgoingContext(ctx, testMetadata) + + stream, err := tc.FullDuplexCall(ctx) + if err != nil { + return reqs, resps, err + } + + if c.callType == cancelRPC { + cancel() + return reqs, resps, context.Canceled + } + + var startID int32 + if !c.success { + startID = errorID + } + for i := 0; i < c.count; i++ { + req := &testpb.SimpleRequest{ + Id: int32(i) + startID, + } + reqs = append(reqs, req) + if err = stream.Send(req); err != nil { + return reqs, resps, err + } + var resp *testpb.SimpleResponse + if resp, err = stream.Recv(); err != nil { + return reqs, resps, err + } + resps = append(resps, resp) + } + if err = stream.CloseSend(); err != nil && err != io.EOF { + return reqs, resps, err + } + if _, err = stream.Recv(); err != io.EOF { + return reqs, resps, err + } + + return reqs, resps, nil +} + +func (te *test) doClientStreamCall(c *rpcConfig) ([]*testpb.SimpleRequest, *testpb.SimpleResponse, error) { + var ( + reqs []*testpb.SimpleRequest + resp *testpb.SimpleResponse + err error + ) + tc := testpb.NewTestServiceClient(te.clientConn()) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + ctx = metadata.NewOutgoingContext(ctx, testMetadata) + + stream, err := tc.ClientStreamCall(ctx) + if err != nil { + return reqs, resp, err + } + var startID int32 + if !c.success { + startID = errorID + } + for i := 0; i < c.count; i++ { + req := &testpb.SimpleRequest{ + Id: int32(i) + startID, + } + reqs = append(reqs, req) + if err = stream.Send(req); err != nil { + return reqs, resp, err + } + } + resp, err = stream.CloseAndRecv() + return reqs, resp, err +} + +func (te *test) doServerStreamCall(c *rpcConfig) (*testpb.SimpleRequest, []*testpb.SimpleResponse, error) { + var ( + req *testpb.SimpleRequest + resps []*testpb.SimpleResponse + err error + ) + + tc := testpb.NewTestServiceClient(te.clientConn()) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + ctx = metadata.NewOutgoingContext(ctx, testMetadata) + + var startID int32 + if !c.success { + startID = errorID + } + req = &testpb.SimpleRequest{Id: startID} + stream, err := tc.ServerStreamCall(ctx, req) + if err != nil { + return req, resps, err + } + for { + var resp *testpb.SimpleResponse + resp, err := stream.Recv() + if err == io.EOF { + return req, resps, nil + } else if err != nil { + return req, resps, err + } + resps = append(resps, resp) + } +} + +type expectedData struct { + te *test + cc *rpcConfig + + method string + requests []*testpb.SimpleRequest + responses []*testpb.SimpleResponse + err error +} + +func (ed *expectedData) newClientHeaderEntry(client bool, rpcID, inRPCID uint64) *pb.GrpcLogEntry { + logger := pb.GrpcLogEntry_LOGGER_CLIENT + var peer *pb.Address + if !client { + logger = pb.GrpcLogEntry_LOGGER_SERVER + ed.te.clientAddrMu.Lock() + peer = &pb.Address{ + Address: ed.te.clientIP.String(), + IpPort: uint32(ed.te.clientPort), + } + if ed.te.clientIP.To4() != nil { + peer.Type = pb.Address_TYPE_IPV4 + } else { + peer.Type = pb.Address_TYPE_IPV6 + } + ed.te.clientAddrMu.Unlock() + } + return &pb.GrpcLogEntry{ + Timestamp: nil, + CallId: rpcID, + SequenceIdWithinCall: inRPCID, + Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER, + Logger: logger, + Payload: &pb.GrpcLogEntry_ClientHeader{ + ClientHeader: &pb.ClientHeader{ + Metadata: binarylog.MdToMetadataProto(testMetadata), + MethodName: ed.method, + Authority: ed.te.srvAddr, + }, + }, + Peer: peer, + } +} + +func (ed *expectedData) newServerHeaderEntry(client bool, rpcID, inRPCID uint64) *pb.GrpcLogEntry { + logger := pb.GrpcLogEntry_LOGGER_SERVER + var peer *pb.Address + if client { + logger = pb.GrpcLogEntry_LOGGER_CLIENT + peer = &pb.Address{ + Address: ed.te.srvIP.String(), + IpPort: uint32(ed.te.srvPort), + } + if ed.te.srvIP.To4() != nil { + peer.Type = pb.Address_TYPE_IPV4 + } else { + peer.Type = pb.Address_TYPE_IPV6 + } + } + return &pb.GrpcLogEntry{ + Timestamp: nil, + CallId: rpcID, + SequenceIdWithinCall: inRPCID, + Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_HEADER, + Logger: logger, + Payload: &pb.GrpcLogEntry_ServerHeader{ + ServerHeader: &pb.ServerHeader{ + Metadata: binarylog.MdToMetadataProto(testMetadata), + }, + }, + Peer: peer, + } +} + +func (ed *expectedData) newClientMessageEntry(client bool, rpcID, inRPCID uint64, msg *testpb.SimpleRequest) *pb.GrpcLogEntry { + logger := pb.GrpcLogEntry_LOGGER_CLIENT + if !client { + logger = pb.GrpcLogEntry_LOGGER_SERVER + } + data, err := proto.Marshal(msg) + if err != nil { + grpclog.Infof("binarylogging_testing: failed to marshal proto message: %v", err) + } + return &pb.GrpcLogEntry{ + Timestamp: nil, + CallId: rpcID, + SequenceIdWithinCall: inRPCID, + Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_MESSAGE, + Logger: logger, + Payload: &pb.GrpcLogEntry_Message{ + Message: &pb.Message{ + Length: uint32(len(data)), + Data: data, + }, + }, + } +} + +func (ed *expectedData) newServerMessageEntry(client bool, rpcID, inRPCID uint64, msg *testpb.SimpleResponse) *pb.GrpcLogEntry { + logger := pb.GrpcLogEntry_LOGGER_CLIENT + if !client { + logger = pb.GrpcLogEntry_LOGGER_SERVER + } + data, err := proto.Marshal(msg) + if err != nil { + grpclog.Infof("binarylogging_testing: failed to marshal proto message: %v", err) + } + return &pb.GrpcLogEntry{ + Timestamp: nil, + CallId: rpcID, + SequenceIdWithinCall: inRPCID, + Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_MESSAGE, + Logger: logger, + Payload: &pb.GrpcLogEntry_Message{ + Message: &pb.Message{ + Length: uint32(len(data)), + Data: data, + }, + }, + } +} + +func (ed *expectedData) newHalfCloseEntry(client bool, rpcID, inRPCID uint64) *pb.GrpcLogEntry { + logger := pb.GrpcLogEntry_LOGGER_CLIENT + if !client { + logger = pb.GrpcLogEntry_LOGGER_SERVER + } + return &pb.GrpcLogEntry{ + Timestamp: nil, + CallId: rpcID, + SequenceIdWithinCall: inRPCID, + Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HALF_CLOSE, + Payload: nil, // No payload here. + Logger: logger, + } +} + +func (ed *expectedData) newServerTrailerEntry(client bool, rpcID, inRPCID uint64, stErr error) *pb.GrpcLogEntry { + logger := pb.GrpcLogEntry_LOGGER_SERVER + var peer *pb.Address + if client { + logger = pb.GrpcLogEntry_LOGGER_CLIENT + peer = &pb.Address{ + Address: ed.te.srvIP.String(), + IpPort: uint32(ed.te.srvPort), + } + if ed.te.srvIP.To4() != nil { + peer.Type = pb.Address_TYPE_IPV4 + } else { + peer.Type = pb.Address_TYPE_IPV6 + } + } + st, ok := status.FromError(stErr) + if !ok { + grpclog.Info("binarylogging: error in trailer is not a status error") + } + stProto := st.Proto() + var ( + detailsBytes []byte + err error + ) + if stProto != nil && len(stProto.Details) != 0 { + detailsBytes, err = proto.Marshal(stProto) + if err != nil { + grpclog.Infof("binarylogging: failed to marshal status proto: %v", err) + } + } + return &pb.GrpcLogEntry{ + Timestamp: nil, + CallId: rpcID, + SequenceIdWithinCall: inRPCID, + Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_TRAILER, + Logger: logger, + Payload: &pb.GrpcLogEntry_Trailer{ + Trailer: &pb.Trailer{ + Metadata: binarylog.MdToMetadataProto(testTrailerMetadata), + // st will be nil if err was not a status error, but nil is ok. + StatusCode: uint32(st.Code()), + StatusMessage: st.Message(), + StatusDetails: detailsBytes, + }, + }, + Peer: peer, + } +} + +func (ed *expectedData) newCancelEntry(rpcID, inRPCID uint64) *pb.GrpcLogEntry { + return &pb.GrpcLogEntry{ + Timestamp: nil, + CallId: rpcID, + SequenceIdWithinCall: inRPCID, + Type: pb.GrpcLogEntry_EVENT_TYPE_CANCEL, + Logger: pb.GrpcLogEntry_LOGGER_CLIENT, + Payload: nil, + } +} + +func (ed *expectedData) toClientLogEntries() []*pb.GrpcLogEntry { + var ( + ret []*pb.GrpcLogEntry + idInRPC uint64 = 1 + ) + ret = append(ret, ed.newClientHeaderEntry(true, globalRPCID, idInRPC)) + idInRPC++ + + switch ed.cc.callType { + case unaryRPC, fullDuplexStreamRPC: + for i := 0; i < len(ed.requests); i++ { + ret = append(ret, ed.newClientMessageEntry(true, globalRPCID, idInRPC, ed.requests[i])) + idInRPC++ + if i == 0 { + // First message, append ServerHeader. + ret = append(ret, ed.newServerHeaderEntry(true, globalRPCID, idInRPC)) + idInRPC++ + } + if !ed.cc.success { + // There is no response in the RPC error case. + continue + } + ret = append(ret, ed.newServerMessageEntry(true, globalRPCID, idInRPC, ed.responses[i])) + idInRPC++ + } + if ed.cc.success && ed.cc.callType == fullDuplexStreamRPC { + ret = append(ret, ed.newHalfCloseEntry(true, globalRPCID, idInRPC)) + idInRPC++ + } + case clientStreamRPC, serverStreamRPC: + for i := 0; i < len(ed.requests); i++ { + ret = append(ret, ed.newClientMessageEntry(true, globalRPCID, idInRPC, ed.requests[i])) + idInRPC++ + } + if ed.cc.callType == clientStreamRPC { + ret = append(ret, ed.newHalfCloseEntry(true, globalRPCID, idInRPC)) + idInRPC++ + } + ret = append(ret, ed.newServerHeaderEntry(true, globalRPCID, idInRPC)) + idInRPC++ + if ed.cc.success { + for i := 0; i < len(ed.responses); i++ { + ret = append(ret, ed.newServerMessageEntry(true, globalRPCID, idInRPC, ed.responses[0])) + idInRPC++ + } + } + } + + if ed.cc.callType == cancelRPC { + ret = append(ret, ed.newCancelEntry(globalRPCID, idInRPC)) + idInRPC++ + } else { + ret = append(ret, ed.newServerTrailerEntry(true, globalRPCID, idInRPC, ed.err)) + idInRPC++ + } + return ret +} + +func (ed *expectedData) toServerLogEntries() []*pb.GrpcLogEntry { + var ( + ret []*pb.GrpcLogEntry + idInRPC uint64 = 1 + ) + ret = append(ret, ed.newClientHeaderEntry(false, globalRPCID, idInRPC)) + idInRPC++ + + switch ed.cc.callType { + case unaryRPC: + ret = append(ret, ed.newClientMessageEntry(false, globalRPCID, idInRPC, ed.requests[0])) + idInRPC++ + ret = append(ret, ed.newServerHeaderEntry(false, globalRPCID, idInRPC)) + idInRPC++ + if ed.cc.success { + ret = append(ret, ed.newServerMessageEntry(false, globalRPCID, idInRPC, ed.responses[0])) + idInRPC++ + } + case fullDuplexStreamRPC: + ret = append(ret, ed.newServerHeaderEntry(false, globalRPCID, idInRPC)) + idInRPC++ + for i := 0; i < len(ed.requests); i++ { + ret = append(ret, ed.newClientMessageEntry(false, globalRPCID, idInRPC, ed.requests[i])) + idInRPC++ + if !ed.cc.success { + // There is no response in the RPC error case. + continue + } + ret = append(ret, ed.newServerMessageEntry(false, globalRPCID, idInRPC, ed.responses[i])) + idInRPC++ + } + + if ed.cc.success && ed.cc.callType == fullDuplexStreamRPC { + ret = append(ret, ed.newHalfCloseEntry(false, globalRPCID, idInRPC)) + idInRPC++ + } + case clientStreamRPC: + ret = append(ret, ed.newServerHeaderEntry(false, globalRPCID, idInRPC)) + idInRPC++ + for i := 0; i < len(ed.requests); i++ { + ret = append(ret, ed.newClientMessageEntry(false, globalRPCID, idInRPC, ed.requests[i])) + idInRPC++ + } + if ed.cc.success { + ret = append(ret, ed.newHalfCloseEntry(false, globalRPCID, idInRPC)) + idInRPC++ + ret = append(ret, ed.newServerMessageEntry(false, globalRPCID, idInRPC, ed.responses[0])) + idInRPC++ + } + case serverStreamRPC: + ret = append(ret, ed.newClientMessageEntry(false, globalRPCID, idInRPC, ed.requests[0])) + idInRPC++ + ret = append(ret, ed.newServerHeaderEntry(false, globalRPCID, idInRPC)) + idInRPC++ + for i := 0; i < len(ed.responses); i++ { + ret = append(ret, ed.newServerMessageEntry(false, globalRPCID, idInRPC, ed.responses[0])) + idInRPC++ + } + } + + ret = append(ret, ed.newServerTrailerEntry(false, globalRPCID, idInRPC, ed.err)) + idInRPC++ + + return ret +} + +func runRPCs(t *testing.T, tc *testConfig, cc *rpcConfig) *expectedData { + te := newTest(t, tc) + te.startServer(&testServer{te: te}) + defer te.tearDown() + + expect := &expectedData{ + te: te, + cc: cc, + } + + switch cc.callType { + case unaryRPC: + expect.method = "/grpc.testing.TestService/UnaryCall" + req, resp, err := te.doUnaryCall(cc) + expect.requests = []*testpb.SimpleRequest{req} + expect.responses = []*testpb.SimpleResponse{resp} + expect.err = err + case clientStreamRPC: + expect.method = "/grpc.testing.TestService/ClientStreamCall" + reqs, resp, err := te.doClientStreamCall(cc) + expect.requests = reqs + expect.responses = []*testpb.SimpleResponse{resp} + expect.err = err + case serverStreamRPC: + expect.method = "/grpc.testing.TestService/ServerStreamCall" + req, resps, err := te.doServerStreamCall(cc) + expect.responses = resps + expect.requests = []*testpb.SimpleRequest{req} + expect.err = err + case fullDuplexStreamRPC, cancelRPC: + expect.method = "/grpc.testing.TestService/FullDuplexCall" + expect.requests, expect.responses, expect.err = te.doFullDuplexCallRoundtrip(cc) + } + if cc.success != (expect.err == nil) { + t.Fatalf("cc.success: %v, got error: %v", cc.success, expect.err) + } + te.cc.Close() + te.srv.GracefulStop() // Wait for the server to stop. + + return expect +} + +// equalLogEntry sorts the metadata entries by key (to compare metadata). +// +// This function is typically called with only two entries. It's written in this +// way so the code can be put in a for loop instead of copied twice. +func equalLogEntry(entries ...*pb.GrpcLogEntry) (equal bool) { + for i, e := range entries { + // Clear out some fields we don't compare. + e.Timestamp = nil + e.CallId = 0 // CallID is global to the binary, hard to compare. + if h := e.GetClientHeader(); h != nil { + h.Timeout = nil + tmp := h.Metadata.Entry[:0] + for _, e := range h.Metadata.Entry { + tmp = append(tmp, e) + } + h.Metadata.Entry = tmp + sort.Slice(h.Metadata.Entry, func(i, j int) bool { return h.Metadata.Entry[i].Key < h.Metadata.Entry[j].Key }) + } + if h := e.GetServerHeader(); h != nil { + tmp := h.Metadata.Entry[:0] + for _, e := range h.Metadata.Entry { + tmp = append(tmp, e) + } + h.Metadata.Entry = tmp + sort.Slice(h.Metadata.Entry, func(i, j int) bool { return h.Metadata.Entry[i].Key < h.Metadata.Entry[j].Key }) + } + if h := e.GetTrailer(); h != nil { + sort.Slice(h.Metadata.Entry, func(i, j int) bool { return h.Metadata.Entry[i].Key < h.Metadata.Entry[j].Key }) + } + + if i > 0 && !proto.Equal(e, entries[i-1]) { + return false + } + } + return true +} + +func testClientBinaryLog(t *testing.T, c *rpcConfig) error { + defer testSink.clear() + expect := runRPCs(t, &testConfig{}, c) + want := expect.toClientLogEntries() + var got []*pb.GrpcLogEntry + // In racy cases, some entries are not logged when the RPC is finished (e.g. + // context.Cancel). + // + // Check 10 times, with a sleep of 1/100 seconds between each check. Makes + // it an 1-second wait in total. + for i := 0; i < 10; i++ { + got = testSink.logEntries(true) // all client entries. + if len(want) == len(got) { + break + } + time.Sleep(100 * time.Millisecond) + } + if len(want) != len(got) { + for i, e := range want { + t.Errorf("in want: %d, %s", i, e.GetType()) + } + for i, e := range got { + t.Errorf("in got: %d, %s", i, e.GetType()) + } + return fmt.Errorf("didn't get same amount of log entries, want: %d, got: %d", len(want), len(got)) + } + var errored bool + for i := 0; i < len(got); i++ { + if !equalLogEntry(want[i], got[i]) { + t.Errorf("entry: %d, want %+v, got %+v", i, want[i], got[i]) + errored = true + } + } + if errored { + return fmt.Errorf("test failed") + } + return nil +} + +func TestClientBinaryLogUnaryRPC(t *testing.T) { + if err := testClientBinaryLog(t, &rpcConfig{success: true, callType: unaryRPC}); err != nil { + t.Fatal(err) + } +} + +func TestClientBinaryLogUnaryRPCError(t *testing.T) { + if err := testClientBinaryLog(t, &rpcConfig{success: false, callType: unaryRPC}); err != nil { + t.Fatal(err) + } +} + +func TestClientBinaryLogClientStreamRPC(t *testing.T) { + count := 5 + if err := testClientBinaryLog(t, &rpcConfig{count: count, success: true, callType: clientStreamRPC}); err != nil { + t.Fatal(err) + } +} + +func TestClientBinaryLogClientStreamRPCError(t *testing.T) { + count := 1 + if err := testClientBinaryLog(t, &rpcConfig{count: count, success: false, callType: clientStreamRPC}); err != nil { + t.Fatal(err) + } +} + +func TestClientBinaryLogServerStreamRPC(t *testing.T) { + count := 5 + if err := testClientBinaryLog(t, &rpcConfig{count: count, success: true, callType: serverStreamRPC}); err != nil { + t.Fatal(err) + } +} + +func TestClientBinaryLogServerStreamRPCError(t *testing.T) { + count := 5 + if err := testClientBinaryLog(t, &rpcConfig{count: count, success: false, callType: serverStreamRPC}); err != nil { + t.Fatal(err) + } +} + +func TestClientBinaryLogFullDuplexRPC(t *testing.T) { + count := 5 + if err := testClientBinaryLog(t, &rpcConfig{count: count, success: true, callType: fullDuplexStreamRPC}); err != nil { + t.Fatal(err) + } +} + +func TestClientBinaryLogFullDuplexRPCError(t *testing.T) { + count := 5 + if err := testClientBinaryLog(t, &rpcConfig{count: count, success: false, callType: fullDuplexStreamRPC}); err != nil { + t.Fatal(err) + } +} + +func TestClientBinaryLogCancel(t *testing.T) { + count := 5 + if err := testClientBinaryLog(t, &rpcConfig{count: count, success: false, callType: cancelRPC}); err != nil { + t.Fatal(err) + } +} + +func testServerBinaryLog(t *testing.T, c *rpcConfig) error { + defer testSink.clear() + expect := runRPCs(t, &testConfig{}, c) + want := expect.toServerLogEntries() + var got []*pb.GrpcLogEntry + // In racy cases, some entries are not logged when the RPC is finished (e.g. + // context.Cancel). This is unlikely to happen on server side, but it does + // no harm to retry. + // + // Check 10 times, with a sleep of 1/100 seconds between each check. Makes + // it an 1-second wait in total. + for i := 0; i < 10; i++ { + got = testSink.logEntries(false) // all server entries. + if len(want) == len(got) { + break + } + time.Sleep(100 * time.Millisecond) + } + + if len(want) != len(got) { + for i, e := range want { + t.Errorf("in want: %d, %s", i, e.GetType()) + } + for i, e := range got { + t.Errorf("in got: %d, %s", i, e.GetType()) + } + return fmt.Errorf("didn't get same amount of log entries, want: %d, got: %d", len(want), len(got)) + } + var errored bool + for i := 0; i < len(got); i++ { + if !equalLogEntry(want[i], got[i]) { + t.Errorf("entry: %d, want %+v, got %+v", i, want[i], got[i]) + errored = true + } + } + if errored { + return fmt.Errorf("test failed") + } + return nil +} + +func TestServerBinaryLogUnaryRPC(t *testing.T) { + if err := testServerBinaryLog(t, &rpcConfig{success: true, callType: unaryRPC}); err != nil { + t.Fatal(err) + } +} + +func TestServerBinaryLogUnaryRPCError(t *testing.T) { + if err := testServerBinaryLog(t, &rpcConfig{success: false, callType: unaryRPC}); err != nil { + t.Fatal(err) + } +} + +func TestServerBinaryLogClientStreamRPC(t *testing.T) { + count := 5 + if err := testServerBinaryLog(t, &rpcConfig{count: count, success: true, callType: clientStreamRPC}); err != nil { + t.Fatal(err) + } +} + +func TestServerBinaryLogClientStreamRPCError(t *testing.T) { + count := 1 + if err := testServerBinaryLog(t, &rpcConfig{count: count, success: false, callType: clientStreamRPC}); err != nil { + t.Fatal(err) + } +} + +func TestServerBinaryLogServerStreamRPC(t *testing.T) { + count := 5 + if err := testServerBinaryLog(t, &rpcConfig{count: count, success: true, callType: serverStreamRPC}); err != nil { + t.Fatal(err) + } +} + +func TestServerBinaryLogServerStreamRPCError(t *testing.T) { + count := 5 + if err := testServerBinaryLog(t, &rpcConfig{count: count, success: false, callType: serverStreamRPC}); err != nil { + t.Fatal(err) + } +} + +func TestServerBinaryLogFullDuplex(t *testing.T) { + count := 5 + if err := testServerBinaryLog(t, &rpcConfig{count: count, success: true, callType: fullDuplexStreamRPC}); err != nil { + t.Fatal(err) + } +} + +func TestServerBinaryLogFullDuplexError(t *testing.T) { + count := 5 + if err := testServerBinaryLog(t, &rpcConfig{count: count, success: false, callType: fullDuplexStreamRPC}); err != nil { + t.Fatal(err) + } +} diff --git a/vendor/google.golang.org/grpc/internal/binarylog/binarylog_test.go b/vendor/google.golang.org/grpc/internal/binarylog/binarylog_test.go new file mode 100644 index 0000000000000000000000000000000000000000..62500a8d1bf30f5a0c5768fd7b1857b1d8716fe5 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/binarylog/binarylog_test.go @@ -0,0 +1,147 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package binarylog + +import ( + "testing" +) + +// Test that get method logger returns the one with the most exact match. +func TestGetMethodLogger(t *testing.T) { + testCases := []struct { + in string + method string + hdr, msg uint64 + }{ + // Global. + { + in: "*{h:12;m:23}", + method: "/s/m", + hdr: 12, msg: 23, + }, + // service/*. + { + in: "*,s/*{h:12;m:23}", + method: "/s/m", + hdr: 12, msg: 23, + }, + // Service/method. + { + in: "*{h;m},s/m{h:12;m:23}", + method: "/s/m", + hdr: 12, msg: 23, + }, + { + in: "*{h;m},s/*{h:314;m},s/m{h:12;m:23}", + method: "/s/m", + hdr: 12, msg: 23, + }, + { + in: "*{h;m},s/*{h:12;m:23},s/m", + method: "/s/m", + hdr: maxUInt, msg: maxUInt, + }, + + // service/*. + { + in: "*{h;m},s/*{h:12;m:23},s/m1", + method: "/s/m", + hdr: 12, msg: 23, + }, + { + in: "*{h;m},s1/*,s/m{h:12;m:23}", + method: "/s/m", + hdr: 12, msg: 23, + }, + + // With black list. + { + in: "*{h:12;m:23},-s/m1", + method: "/s/m", + hdr: 12, msg: 23, + }, + } + for _, tc := range testCases { + l := NewLoggerFromConfigString(tc.in) + if l == nil { + t.Errorf("in: %q, failed to create logger from config string", tc.in) + continue + } + ml := l.getMethodLogger(tc.method) + if ml == nil { + t.Errorf("in: %q, method logger is nil, want non-nil", tc.in) + continue + } + + if ml.headerMaxLen != tc.hdr || ml.messageMaxLen != tc.msg { + t.Errorf("in: %q, want header: %v, message: %v, got header: %v, message: %v", tc.in, tc.hdr, tc.msg, ml.headerMaxLen, ml.messageMaxLen) + } + } +} + +// expect method logger to be nil +func TestGetMethodLoggerOff(t *testing.T) { + testCases := []struct { + in string + method string + }{ + // method not specified. + { + in: "s1/m", + method: "/s/m", + }, + { + in: "s/m1", + method: "/s/m", + }, + { + in: "s1/*", + method: "/s/m", + }, + { + in: "s1/*,s/m1", + method: "/s/m", + }, + + // blacklisted. + { + in: "*,-s/m", + method: "/s/m", + }, + { + in: "s/*,-s/m", + method: "/s/m", + }, + { + in: "-s/m,s/*", + method: "/s/m", + }, + } + for _, tc := range testCases { + l := NewLoggerFromConfigString(tc.in) + if l == nil { + t.Errorf("in: %q, failed to create logger from config string", tc.in) + continue + } + ml := l.getMethodLogger(tc.method) + if ml != nil { + t.Errorf("in: %q, method logger is non-nil, want nil", tc.in) + } + } +} diff --git a/vendor/google.golang.org/grpc/internal/binarylog/binarylog_testutil.go b/vendor/google.golang.org/grpc/internal/binarylog/binarylog_testutil.go new file mode 100644 index 0000000000000000000000000000000000000000..1ee00a39ac7c7b66689ccc7eae1bf475f66df306 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/binarylog/binarylog_testutil.go @@ -0,0 +1,42 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// This file contains exported variables/functions that are exported for testing +// only. +// +// An ideal way for this would be to put those in a *_test.go but in binarylog +// package. But this doesn't work with staticcheck with go module. Error was: +// "MdToMetadataProto not declared by package binarylog". This could be caused +// by the way staticcheck looks for files for a certain package, which doesn't +// support *_test.go files. +// +// Move those to binary_test.go when staticcheck is fixed. + +package binarylog + +var ( + // AllLogger is a logger that logs all headers/messages for all RPCs. It's + // for testing only. + AllLogger = NewLoggerFromConfigString("*") + // MdToMetadataProto converts metadata to a binary logging proto message. + // It's for testing only. + MdToMetadataProto = mdToMetadataProto + // AddrToProto converts an address to a binary logging proto message. It's + // for testing only. + AddrToProto = addrToProto +) diff --git a/vendor/google.golang.org/grpc/internal/binarylog/env_config.go b/vendor/google.golang.org/grpc/internal/binarylog/env_config.go new file mode 100644 index 0000000000000000000000000000000000000000..eb188eae5a3e99dcac06858caa4565780d58bf9d --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/binarylog/env_config.go @@ -0,0 +1,210 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package binarylog + +import ( + "errors" + "fmt" + "regexp" + "strconv" + "strings" + + "google.golang.org/grpc/grpclog" +) + +// NewLoggerFromConfigString reads the string and build a logger. It can be used +// to build a new logger and assign it to binarylog.Logger. +// +// Example filter config strings: +// - "" Nothing will be logged +// - "*" All headers and messages will be fully logged. +// - "*{h}" Only headers will be logged. +// - "*{m:256}" Only the first 256 bytes of each message will be logged. +// - "Foo/*" Logs every method in service Foo +// - "Foo/*,-Foo/Bar" Logs every method in service Foo except method /Foo/Bar +// - "Foo/*,Foo/Bar{m:256}" Logs the first 256 bytes of each message in method +// /Foo/Bar, logs all headers and messages in every other method in service +// Foo. +// +// If two configs exist for one certain method or service, the one specified +// later overrides the privous config. +func NewLoggerFromConfigString(s string) Logger { + if s == "" { + return nil + } + l := newEmptyLogger() + methods := strings.Split(s, ",") + for _, method := range methods { + if err := l.fillMethodLoggerWithConfigString(method); err != nil { + grpclog.Warningf("failed to parse binary log config: %v", err) + return nil + } + } + return l +} + +// fillMethodLoggerWithConfigString parses config, creates methodLogger and adds +// it to the right map in the logger. +func (l *logger) fillMethodLoggerWithConfigString(config string) error { + // "" is invalid. + if config == "" { + return errors.New("empty string is not a valid method binary logging config") + } + + // "-service/method", blacklist, no * or {} allowed. + if config[0] == '-' { + s, m, suffix, err := parseMethodConfigAndSuffix(config[1:]) + if err != nil { + return fmt.Errorf("invalid config: %q, %v", config, err) + } + if m == "*" { + return fmt.Errorf("invalid config: %q, %v", config, "* not allowd in blacklist config") + } + if suffix != "" { + return fmt.Errorf("invalid config: %q, %v", config, "header/message limit not allowed in blacklist config") + } + if err := l.setBlacklist(s + "/" + m); err != nil { + return fmt.Errorf("invalid config: %v", err) + } + return nil + } + + // "*{h:256;m:256}" + if config[0] == '*' { + hdr, msg, err := parseHeaderMessageLengthConfig(config[1:]) + if err != nil { + return fmt.Errorf("invalid config: %q, %v", config, err) + } + if err := l.setDefaultMethodLogger(&methodLoggerConfig{hdr: hdr, msg: msg}); err != nil { + return fmt.Errorf("invalid config: %v", err) + } + return nil + } + + s, m, suffix, err := parseMethodConfigAndSuffix(config) + if err != nil { + return fmt.Errorf("invalid config: %q, %v", config, err) + } + hdr, msg, err := parseHeaderMessageLengthConfig(suffix) + if err != nil { + return fmt.Errorf("invalid header/message length config: %q, %v", suffix, err) + } + if m == "*" { + if err := l.setServiceMethodLogger(s, &methodLoggerConfig{hdr: hdr, msg: msg}); err != nil { + return fmt.Errorf("invalid config: %v", err) + } + } else { + if err := l.setMethodMethodLogger(s+"/"+m, &methodLoggerConfig{hdr: hdr, msg: msg}); err != nil { + return fmt.Errorf("invalid config: %v", err) + } + } + return nil +} + +const ( + // TODO: this const is only used by env_config now. But could be useful for + // other config. Move to binarylog.go if necessary. + maxUInt = ^uint64(0) + + // For "p.s/m" plus any suffix. Suffix will be parsed again. See test for + // expected output. + longMethodConfigRegexpStr = `^([\w./]+)/((?:\w+)|[*])(.+)?$` + + // For suffix from above, "{h:123,m:123}". See test for expected output. + optionalLengthRegexpStr = `(?::(\d+))?` // Optional ":123". + headerConfigRegexpStr = `^{h` + optionalLengthRegexpStr + `}$` + messageConfigRegexpStr = `^{m` + optionalLengthRegexpStr + `}$` + headerMessageConfigRegexpStr = `^{h` + optionalLengthRegexpStr + `;m` + optionalLengthRegexpStr + `}$` +) + +var ( + longMethodConfigRegexp = regexp.MustCompile(longMethodConfigRegexpStr) + headerConfigRegexp = regexp.MustCompile(headerConfigRegexpStr) + messageConfigRegexp = regexp.MustCompile(messageConfigRegexpStr) + headerMessageConfigRegexp = regexp.MustCompile(headerMessageConfigRegexpStr) +) + +// Turn "service/method{h;m}" into "service", "method", "{h;m}". +func parseMethodConfigAndSuffix(c string) (service, method, suffix string, _ error) { + // Regexp result: + // + // in: "p.s/m{h:123,m:123}", + // out: []string{"p.s/m{h:123,m:123}", "p.s", "m", "{h:123,m:123}"}, + match := longMethodConfigRegexp.FindStringSubmatch(c) + if match == nil { + return "", "", "", fmt.Errorf("%q contains invalid substring", c) + } + service = match[1] + method = match[2] + suffix = match[3] + return +} + +// Turn "{h:123;m:345}" into 123, 345. +// +// Return maxUInt if length is unspecified. +func parseHeaderMessageLengthConfig(c string) (hdrLenStr, msgLenStr uint64, err error) { + if c == "" { + return maxUInt, maxUInt, nil + } + // Header config only. + if match := headerConfigRegexp.FindStringSubmatch(c); match != nil { + if s := match[1]; s != "" { + hdrLenStr, err = strconv.ParseUint(s, 10, 64) + if err != nil { + return 0, 0, fmt.Errorf("failed to convert %q to uint", s) + } + return hdrLenStr, 0, nil + } + return maxUInt, 0, nil + } + + // Message config only. + if match := messageConfigRegexp.FindStringSubmatch(c); match != nil { + if s := match[1]; s != "" { + msgLenStr, err = strconv.ParseUint(s, 10, 64) + if err != nil { + return 0, 0, fmt.Errorf("Failed to convert %q to uint", s) + } + return 0, msgLenStr, nil + } + return 0, maxUInt, nil + } + + // Header and message config both. + if match := headerMessageConfigRegexp.FindStringSubmatch(c); match != nil { + // Both hdr and msg are specified, but one or two of them might be empty. + hdrLenStr = maxUInt + msgLenStr = maxUInt + if s := match[1]; s != "" { + hdrLenStr, err = strconv.ParseUint(s, 10, 64) + if err != nil { + return 0, 0, fmt.Errorf("Failed to convert %q to uint", s) + } + } + if s := match[2]; s != "" { + msgLenStr, err = strconv.ParseUint(s, 10, 64) + if err != nil { + return 0, 0, fmt.Errorf("Failed to convert %q to uint", s) + } + } + return hdrLenStr, msgLenStr, nil + } + return 0, 0, fmt.Errorf("%q contains invalid substring", c) +} diff --git a/vendor/google.golang.org/grpc/internal/binarylog/env_config_test.go b/vendor/google.golang.org/grpc/internal/binarylog/env_config_test.go new file mode 100644 index 0000000000000000000000000000000000000000..aced5d5585d819ef1d84ac21d12ec6f5b23dd031 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/binarylog/env_config_test.go @@ -0,0 +1,478 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package binarylog + +import ( + "fmt" + "testing" +) + +// This tests that when multiple configs are specified, all methods loggers will +// be set correctly. Correctness of each logger is covered by other unit tests. +func TestNewLoggerFromConfigString(t *testing.T) { + const ( + s1 = "s1" + m1 = "m1" + m2 = "m2" + fullM1 = s1 + "/" + m1 + fullM2 = s1 + "/" + m2 + ) + c := fmt.Sprintf("*{h:1;m:2},%s{h},%s{m},%s{h;m}", s1+"/*", fullM1, fullM2) + l := NewLoggerFromConfigString(c).(*logger) + + if l.all.hdr != 1 || l.all.msg != 2 { + t.Errorf("l.all = %#v, want headerLen: 1, messageLen: 2", l.all) + } + + if ml, ok := l.services[s1]; ok { + if ml.hdr != maxUInt || ml.msg != 0 { + t.Errorf("want maxUInt header, 0 message, got header: %v, message: %v", ml.hdr, ml.msg) + } + } else { + t.Errorf("service/* is not set") + } + + if ml, ok := l.methods[fullM1]; ok { + if ml.hdr != 0 || ml.msg != maxUInt { + t.Errorf("want 0 header, maxUInt message, got header: %v, message: %v", ml.hdr, ml.msg) + } + } else { + t.Errorf("service/method{h} is not set") + } + + if ml, ok := l.methods[fullM2]; ok { + if ml.hdr != maxUInt || ml.msg != maxUInt { + t.Errorf("want maxUInt header, maxUInt message, got header: %v, message: %v", ml.hdr, ml.msg) + } + } else { + t.Errorf("service/method{h;m} is not set") + } +} + +func TestNewLoggerFromConfigStringInvalid(t *testing.T) { + testCases := []string{ + "", + "*{}", + "s/m,*{}", + "s/m,s/m{a}", + + // Duplciate rules. + "s/m,-s/m", + "-s/m,s/m", + "s/m,s/m", + "s/m,s/m{h:1;m:1}", + "s/m{h:1;m:1},s/m", + "-s/m,-s/m", + "s/*,s/*{h:1;m:1}", + "*,*{h:1;m:1}", + } + for _, tc := range testCases { + l := NewLoggerFromConfigString(tc) + if l != nil { + t.Errorf("With config %q, want logger %v, got %v", tc, nil, l) + } + } +} + +func TestParseMethodConfigAndSuffix(t *testing.T) { + testCases := []struct { + in, service, method, suffix string + }{ + { + in: "p.s/m", + service: "p.s", method: "m", suffix: "", + }, + { + in: "p.s/m{h,m}", + service: "p.s", method: "m", suffix: "{h,m}", + }, + { + in: "p.s/*", + service: "p.s", method: "*", suffix: "", + }, + { + in: "p.s/*{h,m}", + service: "p.s", method: "*", suffix: "{h,m}", + }, + + // invalid suffix will be detected by another function. + { + in: "p.s/m{invalidsuffix}", + service: "p.s", method: "m", suffix: "{invalidsuffix}", + }, + { + in: "p.s/*{invalidsuffix}", + service: "p.s", method: "*", suffix: "{invalidsuffix}", + }, + { + in: "s/m*", + service: "s", method: "m", suffix: "*", + }, + { + in: "s/*m", + service: "s", method: "*", suffix: "m", + }, + { + in: "s/**", + service: "s", method: "*", suffix: "*", + }, + } + for _, tc := range testCases { + t.Logf("testing parseMethodConfigAndSuffix(%q)", tc.in) + s, m, suffix, err := parseMethodConfigAndSuffix(tc.in) + if err != nil { + t.Errorf("returned error %v, want nil", err) + continue + } + if s != tc.service { + t.Errorf("service = %q, want %q", s, tc.service) + } + if m != tc.method { + t.Errorf("method = %q, want %q", m, tc.method) + } + if suffix != tc.suffix { + t.Errorf("suffix = %q, want %q", suffix, tc.suffix) + } + } +} + +func TestParseMethodConfigAndSuffixInvalid(t *testing.T) { + testCases := []string{ + "*/m", + "*/m{}", + } + for _, tc := range testCases { + s, m, suffix, err := parseMethodConfigAndSuffix(tc) + if err == nil { + t.Errorf("Parsing %q got nil error with %q, %q, %q, want non-nil error", tc, s, m, suffix) + } + } +} + +func TestParseHeaderMessageLengthConfig(t *testing.T) { + testCases := []struct { + in string + hdr, msg uint64 + }{ + { + in: "", + hdr: maxUInt, msg: maxUInt, + }, + { + in: "{h}", + hdr: maxUInt, msg: 0, + }, + { + in: "{h:314}", + hdr: 314, msg: 0, + }, + { + in: "{m}", + hdr: 0, msg: maxUInt, + }, + { + in: "{m:213}", + hdr: 0, msg: 213, + }, + { + in: "{h;m}", + hdr: maxUInt, msg: maxUInt, + }, + { + in: "{h:314;m}", + hdr: 314, msg: maxUInt, + }, + { + in: "{h;m:213}", + hdr: maxUInt, msg: 213, + }, + { + in: "{h:314;m:213}", + hdr: 314, msg: 213, + }, + } + for _, tc := range testCases { + t.Logf("testing parseHeaderMessageLengthConfig(%q)", tc.in) + hdr, msg, err := parseHeaderMessageLengthConfig(tc.in) + if err != nil { + t.Errorf("returned error %v, want nil", err) + continue + } + if hdr != tc.hdr { + t.Errorf("header length = %v, want %v", hdr, tc.hdr) + } + if msg != tc.msg { + t.Errorf("message length = %v, want %v", msg, tc.msg) + } + } +} +func TestParseHeaderMessageLengthConfigInvalid(t *testing.T) { + testCases := []string{ + "{}", + "{h;a}", + "{h;m;b}", + } + for _, tc := range testCases { + _, _, err := parseHeaderMessageLengthConfig(tc) + if err == nil { + t.Errorf("Parsing %q got nil error, want non-nil error", tc) + } + } +} + +func TestFillMethodLoggerWithConfigStringBlacklist(t *testing.T) { + testCases := []string{ + "p.s/m", + "service/method", + } + for _, tc := range testCases { + c := "-" + tc + t.Logf("testing fillMethodLoggerWithConfigString(%q)", c) + l := newEmptyLogger() + if err := l.fillMethodLoggerWithConfigString(c); err != nil { + t.Errorf("returned err %v, want nil", err) + continue + } + _, ok := l.blacklist[tc] + if !ok { + t.Errorf("blacklist[%q] is not set", tc) + } + } +} + +func TestFillMethodLoggerWithConfigStringGlobal(t *testing.T) { + testCases := []struct { + in string + hdr, msg uint64 + }{ + { + in: "", + hdr: maxUInt, msg: maxUInt, + }, + { + in: "{h}", + hdr: maxUInt, msg: 0, + }, + { + in: "{h:314}", + hdr: 314, msg: 0, + }, + { + in: "{m}", + hdr: 0, msg: maxUInt, + }, + { + in: "{m:213}", + hdr: 0, msg: 213, + }, + { + in: "{h;m}", + hdr: maxUInt, msg: maxUInt, + }, + { + in: "{h:314;m}", + hdr: 314, msg: maxUInt, + }, + { + in: "{h;m:213}", + hdr: maxUInt, msg: 213, + }, + { + in: "{h:314;m:213}", + hdr: 314, msg: 213, + }, + } + for _, tc := range testCases { + c := "*" + tc.in + t.Logf("testing fillMethodLoggerWithConfigString(%q)", c) + l := newEmptyLogger() + if err := l.fillMethodLoggerWithConfigString(c); err != nil { + t.Errorf("returned err %v, want nil", err) + continue + } + if l.all == nil { + t.Errorf("l.all is not set") + continue + } + if hdr := l.all.hdr; hdr != tc.hdr { + t.Errorf("header length = %v, want %v", hdr, tc.hdr) + + } + if msg := l.all.msg; msg != tc.msg { + t.Errorf("message length = %v, want %v", msg, tc.msg) + } + } +} + +func TestFillMethodLoggerWithConfigStringPerService(t *testing.T) { + testCases := []struct { + in string + hdr, msg uint64 + }{ + { + in: "", + hdr: maxUInt, msg: maxUInt, + }, + { + in: "{h}", + hdr: maxUInt, msg: 0, + }, + { + in: "{h:314}", + hdr: 314, msg: 0, + }, + { + in: "{m}", + hdr: 0, msg: maxUInt, + }, + { + in: "{m:213}", + hdr: 0, msg: 213, + }, + { + in: "{h;m}", + hdr: maxUInt, msg: maxUInt, + }, + { + in: "{h:314;m}", + hdr: 314, msg: maxUInt, + }, + { + in: "{h;m:213}", + hdr: maxUInt, msg: 213, + }, + { + in: "{h:314;m:213}", + hdr: 314, msg: 213, + }, + } + const serviceName = "service" + for _, tc := range testCases { + c := serviceName + "/*" + tc.in + t.Logf("testing fillMethodLoggerWithConfigString(%q)", c) + l := newEmptyLogger() + if err := l.fillMethodLoggerWithConfigString(c); err != nil { + t.Errorf("returned err %v, want nil", err) + continue + } + ml, ok := l.services[serviceName] + if !ok { + t.Errorf("l.service[%q] is not set", serviceName) + continue + } + if hdr := ml.hdr; hdr != tc.hdr { + t.Errorf("header length = %v, want %v", hdr, tc.hdr) + + } + if msg := ml.msg; msg != tc.msg { + t.Errorf("message length = %v, want %v", msg, tc.msg) + } + } +} + +func TestFillMethodLoggerWithConfigStringPerMethod(t *testing.T) { + testCases := []struct { + in string + hdr, msg uint64 + }{ + { + in: "", + hdr: maxUInt, msg: maxUInt, + }, + { + in: "{h}", + hdr: maxUInt, msg: 0, + }, + { + in: "{h:314}", + hdr: 314, msg: 0, + }, + { + in: "{m}", + hdr: 0, msg: maxUInt, + }, + { + in: "{m:213}", + hdr: 0, msg: 213, + }, + { + in: "{h;m}", + hdr: maxUInt, msg: maxUInt, + }, + { + in: "{h:314;m}", + hdr: 314, msg: maxUInt, + }, + { + in: "{h;m:213}", + hdr: maxUInt, msg: 213, + }, + { + in: "{h:314;m:213}", + hdr: 314, msg: 213, + }, + } + const ( + serviceName = "service" + methodName = "method" + fullMethodName = serviceName + "/" + methodName + ) + for _, tc := range testCases { + c := fullMethodName + tc.in + t.Logf("testing fillMethodLoggerWithConfigString(%q)", c) + l := newEmptyLogger() + if err := l.fillMethodLoggerWithConfigString(c); err != nil { + t.Errorf("returned err %v, want nil", err) + continue + } + ml, ok := l.methods[fullMethodName] + if !ok { + t.Errorf("l.methods[%q] is not set", fullMethodName) + continue + } + if hdr := ml.hdr; hdr != tc.hdr { + t.Errorf("header length = %v, want %v", hdr, tc.hdr) + + } + if msg := ml.msg; msg != tc.msg { + t.Errorf("message length = %v, want %v", msg, tc.msg) + } + } +} + +func TestFillMethodLoggerWithConfigStringInvalid(t *testing.T) { + testCases := []string{ + "", + "{}", + "p.s/m{}", + "p.s/m{a}", + "p.s/m*", + "p.s/**", + "*/m", + + "-p.s/*", + "-p.s/m{h}", + } + l := &logger{} + for _, tc := range testCases { + if err := l.fillMethodLoggerWithConfigString(tc); err == nil { + t.Errorf("fillMethodLoggerWithConfigString(%q) returned nil error, want non-nil", tc) + } + } +} diff --git a/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go b/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go new file mode 100644 index 0000000000000000000000000000000000000000..b06cdd4d43b4196a77208e7b5fcf5d1a455b2153 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go @@ -0,0 +1,426 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package binarylog + +import ( + "net" + "strings" + "sync/atomic" + "time" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + pb "google.golang.org/grpc/binarylog/grpc_binarylog_v1" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +type callIDGenerator struct { + id uint64 +} + +func (g *callIDGenerator) next() uint64 { + id := atomic.AddUint64(&g.id, 1) + return id +} + +// reset is for testing only, and doesn't need to be thread safe. +func (g *callIDGenerator) reset() { + g.id = 0 +} + +var idGen callIDGenerator + +// MethodLogger is the sub-logger for each method. +type MethodLogger struct { + headerMaxLen, messageMaxLen uint64 + + callID uint64 + idWithinCallGen *callIDGenerator + + sink Sink // TODO(blog): make this plugable. +} + +func newMethodLogger(h, m uint64) *MethodLogger { + return &MethodLogger{ + headerMaxLen: h, + messageMaxLen: m, + + callID: idGen.next(), + idWithinCallGen: &callIDGenerator{}, + + sink: defaultSink, // TODO(blog): make it plugable. + } +} + +// Log creates a proto binary log entry, and logs it to the sink. +func (ml *MethodLogger) Log(c LogEntryConfig) { + m := c.toProto() + timestamp, _ := ptypes.TimestampProto(time.Now()) + m.Timestamp = timestamp + m.CallId = ml.callID + m.SequenceIdWithinCall = ml.idWithinCallGen.next() + + switch pay := m.Payload.(type) { + case *pb.GrpcLogEntry_ClientHeader: + m.PayloadTruncated = ml.truncateMetadata(pay.ClientHeader.GetMetadata()) + case *pb.GrpcLogEntry_ServerHeader: + m.PayloadTruncated = ml.truncateMetadata(pay.ServerHeader.GetMetadata()) + case *pb.GrpcLogEntry_Message: + m.PayloadTruncated = ml.truncateMessage(pay.Message) + } + + ml.sink.Write(m) +} + +func (ml *MethodLogger) truncateMetadata(mdPb *pb.Metadata) (truncated bool) { + if ml.headerMaxLen == maxUInt { + return false + } + var ( + bytesLimit = ml.headerMaxLen + index int + ) + // At the end of the loop, index will be the first entry where the total + // size is greater than the limit: + // + // len(entry[:index]) <= ml.hdr && len(entry[:index+1]) > ml.hdr. + for ; index < len(mdPb.Entry); index++ { + entry := mdPb.Entry[index] + if entry.Key == "grpc-trace-bin" { + // "grpc-trace-bin" is a special key. It's kept in the log entry, + // but not counted towards the size limit. + continue + } + currentEntryLen := uint64(len(entry.Value)) + if currentEntryLen > bytesLimit { + break + } + bytesLimit -= currentEntryLen + } + truncated = index < len(mdPb.Entry) + mdPb.Entry = mdPb.Entry[:index] + return truncated +} + +func (ml *MethodLogger) truncateMessage(msgPb *pb.Message) (truncated bool) { + if ml.messageMaxLen == maxUInt { + return false + } + if ml.messageMaxLen >= uint64(len(msgPb.Data)) { + return false + } + msgPb.Data = msgPb.Data[:ml.messageMaxLen] + return true +} + +// LogEntryConfig represents the configuration for binary log entry. +type LogEntryConfig interface { + toProto() *pb.GrpcLogEntry +} + +// ClientHeader configs the binary log entry to be a ClientHeader entry. +type ClientHeader struct { + OnClientSide bool + Header metadata.MD + MethodName string + Authority string + Timeout time.Duration + // PeerAddr is required only when it's on server side. + PeerAddr net.Addr +} + +func (c *ClientHeader) toProto() *pb.GrpcLogEntry { + // This function doesn't need to set all the fields (e.g. seq ID). The Log + // function will set the fields when necessary. + clientHeader := &pb.ClientHeader{ + Metadata: mdToMetadataProto(c.Header), + MethodName: c.MethodName, + Authority: c.Authority, + } + if c.Timeout > 0 { + clientHeader.Timeout = ptypes.DurationProto(c.Timeout) + } + ret := &pb.GrpcLogEntry{ + Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER, + Payload: &pb.GrpcLogEntry_ClientHeader{ + ClientHeader: clientHeader, + }, + } + if c.OnClientSide { + ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT + } else { + ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER + } + if c.PeerAddr != nil { + ret.Peer = addrToProto(c.PeerAddr) + } + return ret +} + +// ServerHeader configs the binary log entry to be a ServerHeader entry. +type ServerHeader struct { + OnClientSide bool + Header metadata.MD + // PeerAddr is required only when it's on client side. + PeerAddr net.Addr +} + +func (c *ServerHeader) toProto() *pb.GrpcLogEntry { + ret := &pb.GrpcLogEntry{ + Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_HEADER, + Payload: &pb.GrpcLogEntry_ServerHeader{ + ServerHeader: &pb.ServerHeader{ + Metadata: mdToMetadataProto(c.Header), + }, + }, + } + if c.OnClientSide { + ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT + } else { + ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER + } + if c.PeerAddr != nil { + ret.Peer = addrToProto(c.PeerAddr) + } + return ret +} + +// ClientMessage configs the binary log entry to be a ClientMessage entry. +type ClientMessage struct { + OnClientSide bool + // Message can be a proto.Message or []byte. Other messages formats are not + // supported. + Message interface{} +} + +func (c *ClientMessage) toProto() *pb.GrpcLogEntry { + var ( + data []byte + err error + ) + if m, ok := c.Message.(proto.Message); ok { + data, err = proto.Marshal(m) + if err != nil { + grpclog.Infof("binarylogging: failed to marshal proto message: %v", err) + } + } else if b, ok := c.Message.([]byte); ok { + data = b + } else { + grpclog.Infof("binarylogging: message to log is neither proto.message nor []byte") + } + ret := &pb.GrpcLogEntry{ + Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_MESSAGE, + Payload: &pb.GrpcLogEntry_Message{ + Message: &pb.Message{ + Length: uint32(len(data)), + Data: data, + }, + }, + } + if c.OnClientSide { + ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT + } else { + ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER + } + return ret +} + +// ServerMessage configs the binary log entry to be a ServerMessage entry. +type ServerMessage struct { + OnClientSide bool + // Message can be a proto.Message or []byte. Other messages formats are not + // supported. + Message interface{} +} + +func (c *ServerMessage) toProto() *pb.GrpcLogEntry { + var ( + data []byte + err error + ) + if m, ok := c.Message.(proto.Message); ok { + data, err = proto.Marshal(m) + if err != nil { + grpclog.Infof("binarylogging: failed to marshal proto message: %v", err) + } + } else if b, ok := c.Message.([]byte); ok { + data = b + } else { + grpclog.Infof("binarylogging: message to log is neither proto.message nor []byte") + } + ret := &pb.GrpcLogEntry{ + Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_MESSAGE, + Payload: &pb.GrpcLogEntry_Message{ + Message: &pb.Message{ + Length: uint32(len(data)), + Data: data, + }, + }, + } + if c.OnClientSide { + ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT + } else { + ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER + } + return ret +} + +// ClientHalfClose configs the binary log entry to be a ClientHalfClose entry. +type ClientHalfClose struct { + OnClientSide bool +} + +func (c *ClientHalfClose) toProto() *pb.GrpcLogEntry { + ret := &pb.GrpcLogEntry{ + Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HALF_CLOSE, + Payload: nil, // No payload here. + } + if c.OnClientSide { + ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT + } else { + ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER + } + return ret +} + +// ServerTrailer configs the binary log entry to be a ServerTrailer entry. +type ServerTrailer struct { + OnClientSide bool + Trailer metadata.MD + // Err is the status error. + Err error + // PeerAddr is required only when it's on client side and the RPC is trailer + // only. + PeerAddr net.Addr +} + +func (c *ServerTrailer) toProto() *pb.GrpcLogEntry { + st, ok := status.FromError(c.Err) + if !ok { + grpclog.Info("binarylogging: error in trailer is not a status error") + } + var ( + detailsBytes []byte + err error + ) + stProto := st.Proto() + if stProto != nil && len(stProto.Details) != 0 { + detailsBytes, err = proto.Marshal(stProto) + if err != nil { + grpclog.Infof("binarylogging: failed to marshal status proto: %v", err) + } + } + ret := &pb.GrpcLogEntry{ + Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_TRAILER, + Payload: &pb.GrpcLogEntry_Trailer{ + Trailer: &pb.Trailer{ + Metadata: mdToMetadataProto(c.Trailer), + StatusCode: uint32(st.Code()), + StatusMessage: st.Message(), + StatusDetails: detailsBytes, + }, + }, + } + if c.OnClientSide { + ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT + } else { + ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER + } + if c.PeerAddr != nil { + ret.Peer = addrToProto(c.PeerAddr) + } + return ret +} + +// Cancel configs the binary log entry to be a Cancel entry. +type Cancel struct { + OnClientSide bool +} + +func (c *Cancel) toProto() *pb.GrpcLogEntry { + ret := &pb.GrpcLogEntry{ + Type: pb.GrpcLogEntry_EVENT_TYPE_CANCEL, + Payload: nil, + } + if c.OnClientSide { + ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT + } else { + ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER + } + return ret +} + +// metadataKeyOmit returns whether the metadata entry with this key should be +// omitted. +func metadataKeyOmit(key string) bool { + switch key { + case "lb-token", ":path", ":authority", "content-encoding", "content-type", "user-agent", "te": + return true + case "grpc-trace-bin": // grpc-trace-bin is special because it's visiable to users. + return false + } + if strings.HasPrefix(key, "grpc-") { + return true + } + return false +} + +func mdToMetadataProto(md metadata.MD) *pb.Metadata { + ret := &pb.Metadata{} + for k, vv := range md { + if metadataKeyOmit(k) { + continue + } + for _, v := range vv { + ret.Entry = append(ret.Entry, + &pb.MetadataEntry{ + Key: k, + Value: []byte(v), + }, + ) + } + } + return ret +} + +func addrToProto(addr net.Addr) *pb.Address { + ret := &pb.Address{} + switch a := addr.(type) { + case *net.TCPAddr: + if a.IP.To4() != nil { + ret.Type = pb.Address_TYPE_IPV4 + } else if a.IP.To16() != nil { + ret.Type = pb.Address_TYPE_IPV6 + } else { + ret.Type = pb.Address_TYPE_UNKNOWN + // Do not set address and port fields. + break + } + ret.Address = a.IP.String() + ret.IpPort = uint32(a.Port) + case *net.UnixAddr: + ret.Type = pb.Address_TYPE_UNIX + ret.Address = a.String() + default: + ret.Type = pb.Address_TYPE_UNKNOWN + } + return ret +} diff --git a/vendor/google.golang.org/grpc/internal/binarylog/method_logger_test.go b/vendor/google.golang.org/grpc/internal/binarylog/method_logger_test.go new file mode 100644 index 0000000000000000000000000000000000000000..177adb6a0f2ffec12394c70bbe90637556556f48 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/binarylog/method_logger_test.go @@ -0,0 +1,542 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package binarylog + +import ( + "bytes" + "fmt" + "net" + "testing" + "time" + + "github.com/golang/protobuf/proto" + dpb "github.com/golang/protobuf/ptypes/duration" + pb "google.golang.org/grpc/binarylog/grpc_binarylog_v1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func TestLog(t *testing.T) { + idGen.reset() + ml := newMethodLogger(10, 10) + // Set sink to testing buffer. + buf := bytes.NewBuffer(nil) + ml.sink = newWriterSink(buf) + + addr := "1.2.3.4" + port := 790 + tcpAddr, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("%v:%d", addr, port)) + addr6 := "2001:1db8:85a3::8a2e:1370:7334" + port6 := 796 + tcpAddr6, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("[%v]:%d", addr6, port6)) + + testProtoMsg := &pb.Message{ + Length: 1, + Data: []byte{'a'}, + } + testProtoBytes, _ := proto.Marshal(testProtoMsg) + + testCases := []struct { + config LogEntryConfig + want *pb.GrpcLogEntry + }{ + { + config: &ClientHeader{ + OnClientSide: false, + Header: map[string][]string{ + "a": {"b", "bb"}, + }, + MethodName: "testservice/testmethod", + Authority: "test.service.io", + Timeout: 2*time.Second + 3*time.Nanosecond, + PeerAddr: tcpAddr, + }, + want: &pb.GrpcLogEntry{ + Timestamp: nil, + CallId: 1, + SequenceIdWithinCall: 0, + Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER, + Logger: pb.GrpcLogEntry_LOGGER_SERVER, + Payload: &pb.GrpcLogEntry_ClientHeader{ + ClientHeader: &pb.ClientHeader{ + Metadata: &pb.Metadata{ + Entry: []*pb.MetadataEntry{ + {Key: "a", Value: []byte{'b'}}, + {Key: "a", Value: []byte{'b', 'b'}}, + }, + }, + MethodName: "testservice/testmethod", + Authority: "test.service.io", + Timeout: &dpb.Duration{ + Seconds: 2, + Nanos: 3, + }, + }, + }, + PayloadTruncated: false, + Peer: &pb.Address{ + Type: pb.Address_TYPE_IPV4, + Address: addr, + IpPort: uint32(port), + }, + }, + }, + { + config: &ClientHeader{ + OnClientSide: false, + MethodName: "testservice/testmethod", + Authority: "test.service.io", + }, + want: &pb.GrpcLogEntry{ + Timestamp: nil, + CallId: 1, + SequenceIdWithinCall: 0, + Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER, + Logger: pb.GrpcLogEntry_LOGGER_SERVER, + Payload: &pb.GrpcLogEntry_ClientHeader{ + ClientHeader: &pb.ClientHeader{ + Metadata: &pb.Metadata{}, + MethodName: "testservice/testmethod", + Authority: "test.service.io", + }, + }, + PayloadTruncated: false, + }, + }, + { + config: &ServerHeader{ + OnClientSide: true, + Header: map[string][]string{ + "a": {"b", "bb"}, + }, + PeerAddr: tcpAddr6, + }, + want: &pb.GrpcLogEntry{ + Timestamp: nil, + CallId: 1, + SequenceIdWithinCall: 0, + Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_HEADER, + Logger: pb.GrpcLogEntry_LOGGER_CLIENT, + Payload: &pb.GrpcLogEntry_ServerHeader{ + ServerHeader: &pb.ServerHeader{ + Metadata: &pb.Metadata{ + Entry: []*pb.MetadataEntry{ + {Key: "a", Value: []byte{'b'}}, + {Key: "a", Value: []byte{'b', 'b'}}, + }, + }, + }, + }, + PayloadTruncated: false, + Peer: &pb.Address{ + Type: pb.Address_TYPE_IPV6, + Address: addr6, + IpPort: uint32(port6), + }, + }, + }, + { + config: &ClientMessage{ + OnClientSide: true, + Message: testProtoMsg, + }, + want: &pb.GrpcLogEntry{ + Timestamp: nil, + CallId: 1, + SequenceIdWithinCall: 0, + Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_MESSAGE, + Logger: pb.GrpcLogEntry_LOGGER_CLIENT, + Payload: &pb.GrpcLogEntry_Message{ + Message: &pb.Message{ + Length: uint32(len(testProtoBytes)), + Data: testProtoBytes, + }, + }, + PayloadTruncated: false, + Peer: nil, + }, + }, + { + config: &ServerMessage{ + OnClientSide: false, + Message: testProtoMsg, + }, + want: &pb.GrpcLogEntry{ + Timestamp: nil, + CallId: 1, + SequenceIdWithinCall: 0, + Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_MESSAGE, + Logger: pb.GrpcLogEntry_LOGGER_SERVER, + Payload: &pb.GrpcLogEntry_Message{ + Message: &pb.Message{ + Length: uint32(len(testProtoBytes)), + Data: testProtoBytes, + }, + }, + PayloadTruncated: false, + Peer: nil, + }, + }, + { + config: &ClientHalfClose{ + OnClientSide: false, + }, + want: &pb.GrpcLogEntry{ + Timestamp: nil, + CallId: 1, + SequenceIdWithinCall: 0, + Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HALF_CLOSE, + Logger: pb.GrpcLogEntry_LOGGER_SERVER, + Payload: nil, + PayloadTruncated: false, + Peer: nil, + }, + }, + { + config: &ServerTrailer{ + OnClientSide: true, + Err: status.Errorf(codes.Unavailable, "test"), + PeerAddr: tcpAddr, + }, + want: &pb.GrpcLogEntry{ + Timestamp: nil, + CallId: 1, + SequenceIdWithinCall: 0, + Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_TRAILER, + Logger: pb.GrpcLogEntry_LOGGER_CLIENT, + Payload: &pb.GrpcLogEntry_Trailer{ + Trailer: &pb.Trailer{ + Metadata: &pb.Metadata{}, + StatusCode: uint32(codes.Unavailable), + StatusMessage: "test", + StatusDetails: nil, + }, + }, + PayloadTruncated: false, + Peer: &pb.Address{ + Type: pb.Address_TYPE_IPV4, + Address: addr, + IpPort: uint32(port), + }, + }, + }, + { // Err is nil, Log OK status. + config: &ServerTrailer{ + OnClientSide: true, + }, + want: &pb.GrpcLogEntry{ + Timestamp: nil, + CallId: 1, + SequenceIdWithinCall: 0, + Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_TRAILER, + Logger: pb.GrpcLogEntry_LOGGER_CLIENT, + Payload: &pb.GrpcLogEntry_Trailer{ + Trailer: &pb.Trailer{ + Metadata: &pb.Metadata{}, + StatusCode: uint32(codes.OK), + StatusMessage: "", + StatusDetails: nil, + }, + }, + PayloadTruncated: false, + Peer: nil, + }, + }, + { + config: &Cancel{ + OnClientSide: true, + }, + want: &pb.GrpcLogEntry{ + Timestamp: nil, + CallId: 1, + SequenceIdWithinCall: 0, + Type: pb.GrpcLogEntry_EVENT_TYPE_CANCEL, + Logger: pb.GrpcLogEntry_LOGGER_CLIENT, + Payload: nil, + PayloadTruncated: false, + Peer: nil, + }, + }, + + // gRPC headers should be omitted. + { + config: &ClientHeader{ + OnClientSide: false, + Header: map[string][]string{ + "grpc-reserved": {"to be omitted"}, + ":authority": {"to be omitted"}, + "a": {"b", "bb"}, + }, + }, + want: &pb.GrpcLogEntry{ + Timestamp: nil, + CallId: 1, + SequenceIdWithinCall: 0, + Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER, + Logger: pb.GrpcLogEntry_LOGGER_SERVER, + Payload: &pb.GrpcLogEntry_ClientHeader{ + ClientHeader: &pb.ClientHeader{ + Metadata: &pb.Metadata{ + Entry: []*pb.MetadataEntry{ + {Key: "a", Value: []byte{'b'}}, + {Key: "a", Value: []byte{'b', 'b'}}, + }, + }, + }, + }, + PayloadTruncated: false, + }, + }, + { + config: &ServerHeader{ + OnClientSide: true, + Header: map[string][]string{ + "grpc-reserved": {"to be omitted"}, + ":authority": {"to be omitted"}, + "a": {"b", "bb"}, + }, + }, + want: &pb.GrpcLogEntry{ + Timestamp: nil, + CallId: 1, + SequenceIdWithinCall: 0, + Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_HEADER, + Logger: pb.GrpcLogEntry_LOGGER_CLIENT, + Payload: &pb.GrpcLogEntry_ServerHeader{ + ServerHeader: &pb.ServerHeader{ + Metadata: &pb.Metadata{ + Entry: []*pb.MetadataEntry{ + {Key: "a", Value: []byte{'b'}}, + {Key: "a", Value: []byte{'b', 'b'}}, + }, + }, + }, + }, + PayloadTruncated: false, + }, + }, + } + for i, tc := range testCases { + buf.Reset() + tc.want.SequenceIdWithinCall = uint64(i + 1) + ml.Log(tc.config) + inSink := new(pb.GrpcLogEntry) + if err := proto.Unmarshal(buf.Bytes()[4:], inSink); err != nil { + t.Errorf("failed to unmarshal bytes in sink to proto: %v", err) + continue + } + inSink.Timestamp = nil // Strip timestamp before comparing. + if !proto.Equal(inSink, tc.want) { + t.Errorf("Log(%+v), in sink: %+v, want %+v", tc.config, inSink, tc.want) + } + } +} + +func TestTruncateMetadataNotTruncated(t *testing.T) { + testCases := []struct { + ml *MethodLogger + mpPb *pb.Metadata + }{ + { + ml: newMethodLogger(maxUInt, maxUInt), + mpPb: &pb.Metadata{ + Entry: []*pb.MetadataEntry{ + {Key: "", Value: []byte{1}}, + }, + }, + }, + { + ml: newMethodLogger(2, maxUInt), + mpPb: &pb.Metadata{ + Entry: []*pb.MetadataEntry{ + {Key: "", Value: []byte{1}}, + }, + }, + }, + { + ml: newMethodLogger(1, maxUInt), + mpPb: &pb.Metadata{ + Entry: []*pb.MetadataEntry{ + {Key: "", Value: nil}, + }, + }, + }, + { + ml: newMethodLogger(2, maxUInt), + mpPb: &pb.Metadata{ + Entry: []*pb.MetadataEntry{ + {Key: "", Value: []byte{1, 1}}, + }, + }, + }, + { + ml: newMethodLogger(2, maxUInt), + mpPb: &pb.Metadata{ + Entry: []*pb.MetadataEntry{ + {Key: "", Value: []byte{1}}, + {Key: "", Value: []byte{1}}, + }, + }, + }, + // "grpc-trace-bin" is kept in log but not counted towards the size + // limit. + { + ml: newMethodLogger(1, maxUInt), + mpPb: &pb.Metadata{ + Entry: []*pb.MetadataEntry{ + {Key: "", Value: []byte{1}}, + {Key: "grpc-trace-bin", Value: []byte("some.trace.key")}, + }, + }, + }, + } + + for i, tc := range testCases { + truncated := tc.ml.truncateMetadata(tc.mpPb) + if truncated { + t.Errorf("test case %v, returned truncated, want not truncated", i) + } + } +} + +func TestTruncateMetadataTruncated(t *testing.T) { + testCases := []struct { + ml *MethodLogger + mpPb *pb.Metadata + + entryLen int + }{ + { + ml: newMethodLogger(2, maxUInt), + mpPb: &pb.Metadata{ + Entry: []*pb.MetadataEntry{ + {Key: "", Value: []byte{1, 1, 1}}, + }, + }, + entryLen: 0, + }, + { + ml: newMethodLogger(2, maxUInt), + mpPb: &pb.Metadata{ + Entry: []*pb.MetadataEntry{ + {Key: "", Value: []byte{1}}, + {Key: "", Value: []byte{1}}, + {Key: "", Value: []byte{1}}, + }, + }, + entryLen: 2, + }, + { + ml: newMethodLogger(2, maxUInt), + mpPb: &pb.Metadata{ + Entry: []*pb.MetadataEntry{ + {Key: "", Value: []byte{1, 1}}, + {Key: "", Value: []byte{1}}, + }, + }, + entryLen: 1, + }, + { + ml: newMethodLogger(2, maxUInt), + mpPb: &pb.Metadata{ + Entry: []*pb.MetadataEntry{ + {Key: "", Value: []byte{1}}, + {Key: "", Value: []byte{1, 1}}, + }, + }, + entryLen: 1, + }, + } + + for i, tc := range testCases { + truncated := tc.ml.truncateMetadata(tc.mpPb) + if !truncated { + t.Errorf("test case %v, returned not truncated, want truncated", i) + continue + } + if len(tc.mpPb.Entry) != tc.entryLen { + t.Errorf("test case %v, entry length: %v, want: %v", i, len(tc.mpPb.Entry), tc.entryLen) + } + } +} + +func TestTruncateMessageNotTruncated(t *testing.T) { + testCases := []struct { + ml *MethodLogger + msgPb *pb.Message + }{ + { + ml: newMethodLogger(maxUInt, maxUInt), + msgPb: &pb.Message{ + Data: []byte{1}, + }, + }, + { + ml: newMethodLogger(maxUInt, 3), + msgPb: &pb.Message{ + Data: []byte{1, 1}, + }, + }, + { + ml: newMethodLogger(maxUInt, 2), + msgPb: &pb.Message{ + Data: []byte{1, 1}, + }, + }, + } + + for i, tc := range testCases { + truncated := tc.ml.truncateMessage(tc.msgPb) + if truncated { + t.Errorf("test case %v, returned truncated, want not truncated", i) + } + } +} + +func TestTruncateMessageTruncated(t *testing.T) { + testCases := []struct { + ml *MethodLogger + msgPb *pb.Message + + oldLength uint32 + }{ + { + ml: newMethodLogger(maxUInt, 2), + msgPb: &pb.Message{ + Length: 3, + Data: []byte{1, 1, 1}, + }, + oldLength: 3, + }, + } + + for i, tc := range testCases { + truncated := tc.ml.truncateMessage(tc.msgPb) + if !truncated { + t.Errorf("test case %v, returned not truncated, want truncated", i) + continue + } + if len(tc.msgPb.Data) != int(tc.ml.messageMaxLen) { + t.Errorf("test case %v, message length: %v, want: %v", i, len(tc.msgPb.Data), tc.ml.messageMaxLen) + } + if tc.msgPb.Length != tc.oldLength { + t.Errorf("test case %v, message.Length field: %v, want: %v", i, tc.msgPb.Length, tc.oldLength) + } + } +} diff --git a/vendor/google.golang.org/grpc/internal/binarylog/regenerate.sh b/vendor/google.golang.org/grpc/internal/binarylog/regenerate.sh new file mode 100755 index 0000000000000000000000000000000000000000..113d40cbe16c604019e3dce3364965e7fbcfdb38 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/binarylog/regenerate.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -eux -o pipefail + +TMP=$(mktemp -d) + +function finish { + rm -rf "$TMP" +} +trap finish EXIT + +pushd "$TMP" +mkdir -p grpc/binarylog/grpc_binarylog_v1 +curl https://raw.githubusercontent.com/grpc/grpc-proto/master/grpc/binlog/v1/binarylog.proto > grpc/binarylog/grpc_binarylog_v1/binarylog.proto + +protoc --go_out=plugins=grpc,paths=source_relative:. -I. grpc/binarylog/grpc_binarylog_v1/*.proto +popd +rm -f ./grpc_binarylog_v1/*.pb.go +cp "$TMP"/grpc/binarylog/grpc_binarylog_v1/*.pb.go ../../binarylog/grpc_binarylog_v1/ + diff --git a/vendor/google.golang.org/grpc/internal/binarylog/regexp_test.go b/vendor/google.golang.org/grpc/internal/binarylog/regexp_test.go new file mode 100644 index 0000000000000000000000000000000000000000..8806a5aa4a00c4cd8ee4fae9d99d153c3df115a8 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/binarylog/regexp_test.go @@ -0,0 +1,179 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package binarylog + +import ( + "reflect" + "testing" +) + +func TestLongMethodConfigRegexp(t *testing.T) { + testCases := []struct { + in string + out []string + }{ + {in: "", out: nil}, + {in: "*/m", out: nil}, + + { + in: "p.s/m{}", + out: []string{"p.s/m{}", "p.s", "m", "{}"}, + }, + + { + in: "p.s/m", + out: []string{"p.s/m", "p.s", "m", ""}, + }, + { + in: "p.s/m{h}", + out: []string{"p.s/m{h}", "p.s", "m", "{h}"}, + }, + { + in: "p.s/m{m}", + out: []string{"p.s/m{m}", "p.s", "m", "{m}"}, + }, + { + in: "p.s/m{h:123}", + out: []string{"p.s/m{h:123}", "p.s", "m", "{h:123}"}, + }, + { + in: "p.s/m{m:123}", + out: []string{"p.s/m{m:123}", "p.s", "m", "{m:123}"}, + }, + { + in: "p.s/m{h:123,m:123}", + out: []string{"p.s/m{h:123,m:123}", "p.s", "m", "{h:123,m:123}"}, + }, + + { + in: "p.s/*", + out: []string{"p.s/*", "p.s", "*", ""}, + }, + { + in: "p.s/*{h}", + out: []string{"p.s/*{h}", "p.s", "*", "{h}"}, + }, + + { + in: "s/m*", + out: []string{"s/m*", "s", "m", "*"}, + }, + { + in: "s/**", + out: []string{"s/**", "s", "*", "*"}, + }, + } + for _, tc := range testCases { + match := longMethodConfigRegexp.FindStringSubmatch(tc.in) + if !reflect.DeepEqual(match, tc.out) { + t.Errorf("in: %q, out: %q, want: %q", tc.in, match, tc.out) + } + } +} + +func TestHeaderConfigRegexp(t *testing.T) { + testCases := []struct { + in string + out []string + }{ + {in: "{}", out: nil}, + {in: "{a:b}", out: nil}, + {in: "{m:123}", out: nil}, + {in: "{h:123;m:123}", out: nil}, + + { + in: "{h}", + out: []string{"{h}", ""}, + }, + { + in: "{h:123}", + out: []string{"{h:123}", "123"}, + }, + } + for _, tc := range testCases { + match := headerConfigRegexp.FindStringSubmatch(tc.in) + if !reflect.DeepEqual(match, tc.out) { + t.Errorf("in: %q, out: %q, want: %q", tc.in, match, tc.out) + } + } +} + +func TestMessageConfigRegexp(t *testing.T) { + testCases := []struct { + in string + out []string + }{ + {in: "{}", out: nil}, + {in: "{a:b}", out: nil}, + {in: "{h:123}", out: nil}, + {in: "{h:123;m:123}", out: nil}, + + { + in: "{m}", + out: []string{"{m}", ""}, + }, + { + in: "{m:123}", + out: []string{"{m:123}", "123"}, + }, + } + for _, tc := range testCases { + match := messageConfigRegexp.FindStringSubmatch(tc.in) + if !reflect.DeepEqual(match, tc.out) { + t.Errorf("in: %q, out: %q, want: %q", tc.in, match, tc.out) + } + } +} + +func TestHeaderMessageConfigRegexp(t *testing.T) { + testCases := []struct { + in string + out []string + }{ + {in: "{}", out: nil}, + {in: "{a:b}", out: nil}, + {in: "{h}", out: nil}, + {in: "{h:123}", out: nil}, + {in: "{m}", out: nil}, + {in: "{m:123}", out: nil}, + + { + in: "{h;m}", + out: []string{"{h;m}", "", ""}, + }, + { + in: "{h:123;m}", + out: []string{"{h:123;m}", "123", ""}, + }, + { + in: "{h;m:123}", + out: []string{"{h;m:123}", "", "123"}, + }, + { + in: "{h:123;m:123}", + out: []string{"{h:123;m:123}", "123", "123"}, + }, + } + for _, tc := range testCases { + match := headerMessageConfigRegexp.FindStringSubmatch(tc.in) + if !reflect.DeepEqual(match, tc.out) { + t.Errorf("in: %q, out: %q, want: %q", tc.in, match, tc.out) + } + } +} diff --git a/vendor/google.golang.org/grpc/internal/binarylog/sink.go b/vendor/google.golang.org/grpc/internal/binarylog/sink.go new file mode 100644 index 0000000000000000000000000000000000000000..20d044f0fd711a64d7636ce7d393bccc6484432b --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/binarylog/sink.go @@ -0,0 +1,162 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package binarylog + +import ( + "bufio" + "encoding/binary" + "fmt" + "io" + "io/ioutil" + "sync" + "time" + + "github.com/golang/protobuf/proto" + pb "google.golang.org/grpc/binarylog/grpc_binarylog_v1" + "google.golang.org/grpc/grpclog" +) + +var ( + defaultSink Sink = &noopSink{} // TODO(blog): change this default (file in /tmp). +) + +// SetDefaultSink sets the sink where binary logs will be written to. +// +// Not thread safe. Only set during initialization. +func SetDefaultSink(s Sink) { + if defaultSink != nil { + defaultSink.Close() + } + defaultSink = s +} + +// Sink writes log entry into the binary log sink. +type Sink interface { + // Write will be called to write the log entry into the sink. + // + // It should be thread-safe so it can be called in parallel. + Write(*pb.GrpcLogEntry) error + // Close will be called when the Sink is replaced by a new Sink. + Close() error +} + +type noopSink struct{} + +func (ns *noopSink) Write(*pb.GrpcLogEntry) error { return nil } +func (ns *noopSink) Close() error { return nil } + +// newWriterSink creates a binary log sink with the given writer. +// +// Write() marshalls the proto message and writes it to the given writer. Each +// message is prefixed with a 4 byte big endian unsigned integer as the length. +// +// No buffer is done, Close() doesn't try to close the writer. +func newWriterSink(w io.Writer) *writerSink { + return &writerSink{out: w} +} + +type writerSink struct { + out io.Writer +} + +func (ws *writerSink) Write(e *pb.GrpcLogEntry) error { + b, err := proto.Marshal(e) + if err != nil { + grpclog.Infof("binary logging: failed to marshal proto message: %v", err) + } + hdr := make([]byte, 4) + binary.BigEndian.PutUint32(hdr, uint32(len(b))) + if _, err := ws.out.Write(hdr); err != nil { + return err + } + if _, err := ws.out.Write(b); err != nil { + return err + } + return nil +} + +func (ws *writerSink) Close() error { return nil } + +type bufWriteCloserSink struct { + mu sync.Mutex + closer io.Closer + out *writerSink // out is built on buf. + buf *bufio.Writer // buf is kept for flush. + + writeStartOnce sync.Once + writeTicker *time.Ticker +} + +func (fs *bufWriteCloserSink) Write(e *pb.GrpcLogEntry) error { + // Start the write loop when Write is called. + fs.writeStartOnce.Do(fs.startFlushGoroutine) + fs.mu.Lock() + if err := fs.out.Write(e); err != nil { + fs.mu.Unlock() + return err + } + fs.mu.Unlock() + return nil +} + +const ( + bufFlushDuration = 60 * time.Second +) + +func (fs *bufWriteCloserSink) startFlushGoroutine() { + fs.writeTicker = time.NewTicker(bufFlushDuration) + go func() { + for range fs.writeTicker.C { + fs.mu.Lock() + fs.buf.Flush() + fs.mu.Unlock() + } + }() +} + +func (fs *bufWriteCloserSink) Close() error { + if fs.writeTicker != nil { + fs.writeTicker.Stop() + } + fs.mu.Lock() + fs.buf.Flush() + fs.closer.Close() + fs.out.Close() + fs.mu.Unlock() + return nil +} + +func newBufWriteCloserSink(o io.WriteCloser) Sink { + bufW := bufio.NewWriter(o) + return &bufWriteCloserSink{ + closer: o, + out: newWriterSink(bufW), + buf: bufW, + } +} + +// NewTempFileSink creates a temp file and returns a Sink that writes to this +// file. +func NewTempFileSink() (Sink, error) { + tempFile, err := ioutil.TempFile("/tmp", "grpcgo_binarylog_*.txt") + if err != nil { + return nil, fmt.Errorf("failed to create temp file: %v", err) + } + return newBufWriteCloserSink(tempFile), nil +} diff --git a/vendor/google.golang.org/grpc/status/go17_test.go b/vendor/google.golang.org/grpc/internal/binarylog/util.go similarity index 51% rename from vendor/google.golang.org/grpc/status/go17_test.go rename to vendor/google.golang.org/grpc/internal/binarylog/util.go index 2dc5add940461f0324af09d4df853c4c132be2ce..15dc7803d8bffd37a06c430cb621d09f809d23e2 100644 --- a/vendor/google.golang.org/grpc/status/go17_test.go +++ b/vendor/google.golang.org/grpc/internal/binarylog/util.go @@ -1,5 +1,3 @@ -// +build go1.7 - /* * * Copyright 2018 gRPC authors. @@ -18,27 +16,26 @@ * */ -package status +package binarylog import ( - "context" - "testing" - - "google.golang.org/grpc/codes" + "errors" + "strings" ) -func TestFromStdContextError(t *testing.T) { - testCases := []struct { - in error - want *Status - }{ - {in: context.DeadlineExceeded, want: New(codes.DeadlineExceeded, context.DeadlineExceeded.Error())}, - {in: context.Canceled, want: New(codes.Canceled, context.Canceled.Error())}, +// parseMethodName splits service and method from the input. It expects format +// "/service/method". +// +// TODO: move to internal/grpcutil. +func parseMethodName(methodName string) (service, method string, _ error) { + if !strings.HasPrefix(methodName, "/") { + return "", "", errors.New("invalid method name: should start with /") } - for _, tc := range testCases { - got := FromContextError(tc.in) - if got.Code() != tc.want.Code() || got.Message() != tc.want.Message() { - t.Errorf("FromContextError(%v) = %v; want %v", tc.in, got, tc.want) - } + methodName = methodName[1:] + + pos := strings.LastIndex(methodName, "/") + if pos < 0 { + return "", "", errors.New("invalid method name: suffix /method is missing") } + return methodName[:pos], methodName[pos+1:], nil } diff --git a/vendor/google.golang.org/grpc/internal/binarylog/util_test.go b/vendor/google.golang.org/grpc/internal/binarylog/util_test.go new file mode 100644 index 0000000000000000000000000000000000000000..3454f029568ab17275180d9ae3acb59a1b865084 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/binarylog/util_test.go @@ -0,0 +1,59 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package binarylog + +import "testing" + +func TestParseMethodName(t *testing.T) { + testCases := []struct { + methodName string + service, method string + }{ + {methodName: "/s/m", service: "s", method: "m"}, + {methodName: "/p.s/m", service: "p.s", method: "m"}, + {methodName: "/p/s/m", service: "p/s", method: "m"}, + } + for _, tc := range testCases { + s, m, err := parseMethodName(tc.methodName) + if err != nil { + t.Errorf("Parsing %q got error %v, want nil", tc.methodName, err) + continue + } + if s != tc.service || m != tc.method { + t.Errorf("Parseing %q got service %q, method %q, want service %q, method %q", + tc.methodName, s, m, tc.service, tc.method, + ) + } + } +} + +func TestParseMethodNameInvalid(t *testing.T) { + testCases := []string{ + "/", + "/sm", + "", + "sm", + } + for _, tc := range testCases { + _, _, err := parseMethodName(tc) + if err == nil { + t.Errorf("Parsing %q got nil error, want non-nil error", tc) + } + } +} diff --git a/vendor/google.golang.org/grpc/internal/channelz/funcs.go b/vendor/google.golang.org/grpc/internal/channelz/funcs.go index 586a0336b473e1d64b26d9d68705792bd75f27f8..3021a31a525cc45e6c304c5d41d5b914f33a80e2 100644 --- a/vendor/google.golang.org/grpc/internal/channelz/funcs.go +++ b/vendor/google.golang.org/grpc/internal/channelz/funcs.go @@ -27,16 +27,22 @@ import ( "sort" "sync" "sync/atomic" + "time" "google.golang.org/grpc/grpclog" ) +const ( + defaultMaxTraceEntry int32 = 30 +) + var ( db dbWrapper idGen idGenerator // EntryPerPage defines the number of channelz entries to be shown on a web page. - EntryPerPage = 50 - curState int32 + EntryPerPage = 50 + curState int32 + maxTraceEntry = defaultMaxTraceEntry ) // TurnOn turns on channelz data collection. @@ -52,6 +58,22 @@ func IsOn() bool { return atomic.CompareAndSwapInt32(&curState, 1, 1) } +// SetMaxTraceEntry sets maximum number of trace entry per entity (i.e. channel/subchannel). +// Setting it to 0 will disable channel tracing. +func SetMaxTraceEntry(i int32) { + atomic.StoreInt32(&maxTraceEntry, i) +} + +// ResetMaxTraceEntryToDefault resets the maximum number of trace entry per entity to default. +func ResetMaxTraceEntryToDefault() { + atomic.StoreInt32(&maxTraceEntry, defaultMaxTraceEntry) +} + +func getMaxTraceEntry() int { + i := atomic.LoadInt32(&maxTraceEntry) + return int(i) +} + // dbWarpper wraps around a reference to internal channelz data storage, and // provide synchronized functionality to set and get the reference. type dbWrapper struct { @@ -146,6 +168,7 @@ func RegisterChannel(c Channel, pid int64, ref string) int64 { nestedChans: make(map[int64]string), id: id, pid: pid, + trace: &channelTrace{createdTime: time.Now(), events: make([]*TraceEvent, 0, getMaxTraceEntry())}, } if pid == 0 { db.get().addChannel(id, cn, true, pid, ref) @@ -170,6 +193,7 @@ func RegisterSubChannel(c Channel, pid int64, ref string) int64 { sockets: make(map[int64]string), id: id, pid: pid, + trace: &channelTrace{createdTime: time.Now(), events: make([]*TraceEvent, 0, getMaxTraceEntry())}, } db.get().addSubChannel(id, sc, pid, ref) return id @@ -226,6 +250,24 @@ func RemoveEntry(id int64) { db.get().removeEntry(id) } +// TraceEventDesc is what the caller of AddTraceEvent should provide to describe the event to be added +// to the channel trace. +// The Parent field is optional. It is used for event that will be recorded in the entity's parent +// trace also. +type TraceEventDesc struct { + Desc string + Severity Severity + Parent *TraceEventDesc +} + +// AddTraceEvent adds trace related to the entity with specified id, using the provided TraceEventDesc. +func AddTraceEvent(id int64, desc *TraceEventDesc) { + if getMaxTraceEntry() == 0 { + return + } + db.get().traceEvent(id, desc) +} + // channelMap is the storage data structure for channelz. // Methods of channelMap can be divided in two two categories with respect to locking. // 1. Methods acquire the global lock. @@ -251,6 +293,7 @@ func (c *channelMap) addServer(id int64, s *server) { func (c *channelMap) addChannel(id int64, cn *channel, isTopChannel bool, pid int64, ref string) { c.mu.Lock() cn.cm = c + cn.trace.cm = c c.channels[id] = cn if isTopChannel { c.topLevelChannels[id] = struct{}{} @@ -263,6 +306,7 @@ func (c *channelMap) addChannel(id int64, cn *channel, isTopChannel bool, pid in func (c *channelMap) addSubChannel(id int64, sc *subChannel, pid int64, ref string) { c.mu.Lock() sc.cm = c + sc.trace.cm = c c.subChannels[id] = sc c.findEntry(pid).addChild(id, sc) c.mu.Unlock() @@ -284,16 +328,25 @@ func (c *channelMap) addNormalSocket(id int64, ns *normalSocket, pid int64, ref c.mu.Unlock() } -// removeEntry triggers the removal of an entry, which may not indeed delete the -// entry, if it has to wait on the deletion of its children, or may lead to a chain -// of entry deletion. For example, deleting the last socket of a gracefully shutting -// down server will lead to the server being also deleted. +// removeEntry triggers the removal of an entry, which may not indeed delete the entry, if it has to +// wait on the deletion of its children and until no other entity's channel trace references it. +// It may lead to a chain of entry deletion. For example, deleting the last socket of a gracefully +// shutting down server will lead to the server being also deleted. func (c *channelMap) removeEntry(id int64) { c.mu.Lock() c.findEntry(id).triggerDelete() c.mu.Unlock() } +// c.mu must be held by the caller +func (c *channelMap) decrTraceRefCount(id int64) { + e := c.findEntry(id) + if v, ok := e.(tracedChannel); ok { + v.decrTraceRefCount() + e.deleteSelfIfReady() + } +} + // c.mu must be held by the caller. func (c *channelMap) findEntry(id int64) entry { var v entry @@ -347,6 +400,39 @@ func (c *channelMap) deleteEntry(id int64) { } } +func (c *channelMap) traceEvent(id int64, desc *TraceEventDesc) { + c.mu.Lock() + child := c.findEntry(id) + childTC, ok := child.(tracedChannel) + if !ok { + c.mu.Unlock() + return + } + childTC.getChannelTrace().append(&TraceEvent{Desc: desc.Desc, Severity: desc.Severity, Timestamp: time.Now()}) + if desc.Parent != nil { + parent := c.findEntry(child.getParentID()) + var chanType RefChannelType + switch child.(type) { + case *channel: + chanType = RefChannel + case *subChannel: + chanType = RefSubChannel + } + if parentTC, ok := parent.(tracedChannel); ok { + parentTC.getChannelTrace().append(&TraceEvent{ + Desc: desc.Parent.Desc, + Severity: desc.Parent.Severity, + Timestamp: time.Now(), + RefID: id, + RefName: childTC.getRefName(), + RefType: chanType, + }) + childTC.incrTraceRefCount() + } + } + c.mu.Unlock() +} + type int64Slice []int64 func (s int64Slice) Len() int { return len(s) } @@ -408,6 +494,7 @@ func (c *channelMap) GetTopChannels(id int64) ([]*ChannelMetric, bool) { t[i].ChannelData = cn.c.ChannelzMetric() t[i].ID = cn.id t[i].RefName = cn.refName + t[i].Trace = cn.trace.dumpData() } return t, end } @@ -470,8 +557,8 @@ func (c *channelMap) GetServerSockets(id int64, startID int64) ([]*SocketMetric, for k := range svrskts { ids = append(ids, k) } - sort.Sort((int64Slice(ids))) - idx := sort.Search(len(ids), func(i int) bool { return ids[i] >= id }) + sort.Sort(int64Slice(ids)) + idx := sort.Search(len(ids), func(i int) bool { return ids[i] >= startID }) count := 0 var end bool for i, v := range ids[idx:] { @@ -514,10 +601,14 @@ func (c *channelMap) GetChannel(id int64) *ChannelMetric { } cm.NestedChans = copyMap(cn.nestedChans) cm.SubChans = copyMap(cn.subChans) + // cn.c can be set to &dummyChannel{} when deleteSelfFromMap is called. Save a copy of cn.c when + // holding the lock to prevent potential data race. + chanCopy := cn.c c.mu.RUnlock() - cm.ChannelData = cn.c.ChannelzMetric() + cm.ChannelData = chanCopy.ChannelzMetric() cm.ID = cn.id cm.RefName = cn.refName + cm.Trace = cn.trace.dumpData() return cm } @@ -532,10 +623,14 @@ func (c *channelMap) GetSubChannel(id int64) *SubChannelMetric { return nil } cm.Sockets = copyMap(sc.sockets) + // sc.c can be set to &dummyChannel{} when deleteSelfFromMap is called. Save a copy of sc.c when + // holding the lock to prevent potential data race. + chanCopy := sc.c c.mu.RUnlock() - cm.ChannelData = sc.c.ChannelzMetric() + cm.ChannelData = chanCopy.ChannelzMetric() cm.ID = sc.id cm.RefName = sc.refName + cm.Trace = sc.trace.dumpData() return cm } diff --git a/vendor/google.golang.org/grpc/internal/channelz/types.go b/vendor/google.golang.org/grpc/internal/channelz/types.go index 153d75340e419cca4093b5c90f0af5d4fb045cf4..17c2274cb3de5cea3ca8a999f38b9a57161c313d 100644 --- a/vendor/google.golang.org/grpc/internal/channelz/types.go +++ b/vendor/google.golang.org/grpc/internal/channelz/types.go @@ -20,9 +20,12 @@ package channelz import ( "net" + "sync" + "sync/atomic" "time" "google.golang.org/grpc/connectivity" + "google.golang.org/grpc/credentials" "google.golang.org/grpc/grpclog" ) @@ -39,6 +42,8 @@ type entry interface { // deleteSelfIfReady check whether triggerDelete() has been called before, and whether child // list is now empty. If both conditions are met, then delete self from database. deleteSelfIfReady() + // getParentID returns parent ID of the entry. 0 value parent ID means no parent. + getParentID() int64 } // dummyEntry is a fake entry to handle entry not found case. @@ -72,6 +77,10 @@ func (*dummyEntry) deleteSelfIfReady() { // code should not reach here. deleteSelfIfReady is always called on an existing entry. } +func (*dummyEntry) getParentID() int64 { + return 0 +} + // ChannelMetric defines the info channelz provides for a specific Channel, which // includes ChannelInternalMetric and channelz-specific data, such as channelz id, // child list, etc. @@ -94,6 +103,8 @@ type ChannelMetric struct { // Note current grpc implementation doesn't allow channel having sockets directly, // therefore, this is field is unused. Sockets map[int64]string + // Trace contains the most recent traced events. + Trace *ChannelTrace } // SubChannelMetric defines the info channelz provides for a specific SubChannel, @@ -120,6 +131,8 @@ type SubChannelMetric struct { // Sockets tracks the socket type children of this subchannel in the format of a map // from socket channelz id to corresponding reference string. Sockets map[int64]string + // Trace contains the most recent traced events. + Trace *ChannelTrace } // ChannelInternalMetric defines the struct that the implementor of Channel interface @@ -137,7 +150,35 @@ type ChannelInternalMetric struct { CallsFailed int64 // The last time a call was started on the channel. LastCallStartedTimestamp time.Time - //TODO: trace +} + +// ChannelTrace stores traced events on a channel/subchannel and related info. +type ChannelTrace struct { + // EventNum is the number of events that ever got traced (i.e. including those that have been deleted) + EventNum int64 + // CreationTime is the creation time of the trace. + CreationTime time.Time + // Events stores the most recent trace events (up to $maxTraceEntry, newer event will overwrite the + // oldest one) + Events []*TraceEvent +} + +// TraceEvent represent a single trace event +type TraceEvent struct { + // Desc is a simple description of the trace event. + Desc string + // Severity states the severity of this trace event. + Severity Severity + // Timestamp is the event time. + Timestamp time.Time + // RefID is the id of the entity that gets referenced in the event. RefID is 0 if no other entity is + // involved in this event. + // e.g. SubChannel (id: 4[]) Created. --> RefID = 4, RefName = "" (inside []) + RefID int64 + // RefName is the reference name for the entity that gets referenced in the event. + RefName string + // RefType indicates the referenced entity type, i.e Channel or SubChannel. + RefType RefChannelType } // Channel is the interface that should be satisfied in order to be tracked by @@ -146,6 +187,12 @@ type Channel interface { ChannelzMetric() *ChannelInternalMetric } +type dummyChannel struct{} + +func (d *dummyChannel) ChannelzMetric() *ChannelInternalMetric { + return &ChannelInternalMetric{} +} + type channel struct { refName string c Channel @@ -155,6 +202,10 @@ type channel struct { id int64 pid int64 cm *channelMap + trace *channelTrace + // traceRefCount is the number of trace events that reference this channel. + // Non-zero traceRefCount means the trace of this channel cannot be deleted. + traceRefCount int32 } func (c *channel) addChild(id int64, e entry) { @@ -179,25 +230,96 @@ func (c *channel) triggerDelete() { c.deleteSelfIfReady() } -func (c *channel) deleteSelfIfReady() { +func (c *channel) getParentID() int64 { + return c.pid +} + +// deleteSelfFromTree tries to delete the channel from the channelz entry relation tree, which means +// deleting the channel reference from its parent's child list. +// +// In order for a channel to be deleted from the tree, it must meet the criteria that, removal of the +// corresponding grpc object has been invoked, and the channel does not have any children left. +// +// The returned boolean value indicates whether the channel has been successfully deleted from tree. +func (c *channel) deleteSelfFromTree() (deleted bool) { if !c.closeCalled || len(c.subChans)+len(c.nestedChans) != 0 { - return + return false } - c.cm.deleteEntry(c.id) // not top channel if c.pid != 0 { c.cm.findEntry(c.pid).deleteChild(c.id) } + return true +} + +// deleteSelfFromMap checks whether it is valid to delete the channel from the map, which means +// deleting the channel from channelz's tracking entirely. Users can no longer use id to query the +// channel, and its memory will be garbage collected. +// +// The trace reference count of the channel must be 0 in order to be deleted from the map. This is +// specified in the channel tracing gRFC that as long as some other trace has reference to an entity, +// the trace of the referenced entity must not be deleted. In order to release the resource allocated +// by grpc, the reference to the grpc object is reset to a dummy object. +// +// deleteSelfFromMap must be called after deleteSelfFromTree returns true. +// +// It returns a bool to indicate whether the channel can be safely deleted from map. +func (c *channel) deleteSelfFromMap() (delete bool) { + if c.getTraceRefCount() != 0 { + c.c = &dummyChannel{} + return false + } + return true +} + +// deleteSelfIfReady tries to delete the channel itself from the channelz database. +// The delete process includes two steps: +// 1. delete the channel from the entry relation tree, i.e. delete the channel reference from its +// parent's child list. +// 2. delete the channel from the map, i.e. delete the channel entirely from channelz. Lookup by id +// will return entry not found error. +func (c *channel) deleteSelfIfReady() { + if !c.deleteSelfFromTree() { + return + } + if !c.deleteSelfFromMap() { + return + } + c.cm.deleteEntry(c.id) + c.trace.clear() +} + +func (c *channel) getChannelTrace() *channelTrace { + return c.trace +} + +func (c *channel) incrTraceRefCount() { + atomic.AddInt32(&c.traceRefCount, 1) +} + +func (c *channel) decrTraceRefCount() { + atomic.AddInt32(&c.traceRefCount, -1) +} + +func (c *channel) getTraceRefCount() int { + i := atomic.LoadInt32(&c.traceRefCount) + return int(i) +} + +func (c *channel) getRefName() string { + return c.refName } type subChannel struct { - refName string - c Channel - closeCalled bool - sockets map[int64]string - id int64 - pid int64 - cm *channelMap + refName string + c Channel + closeCalled bool + sockets map[int64]string + id int64 + pid int64 + cm *channelMap + trace *channelTrace + traceRefCount int32 } func (sc *subChannel) addChild(id int64, e entry) { @@ -218,12 +340,82 @@ func (sc *subChannel) triggerDelete() { sc.deleteSelfIfReady() } -func (sc *subChannel) deleteSelfIfReady() { +func (sc *subChannel) getParentID() int64 { + return sc.pid +} + +// deleteSelfFromTree tries to delete the subchannel from the channelz entry relation tree, which +// means deleting the subchannel reference from its parent's child list. +// +// In order for a subchannel to be deleted from the tree, it must meet the criteria that, removal of +// the corresponding grpc object has been invoked, and the subchannel does not have any children left. +// +// The returned boolean value indicates whether the channel has been successfully deleted from tree. +func (sc *subChannel) deleteSelfFromTree() (deleted bool) { if !sc.closeCalled || len(sc.sockets) != 0 { + return false + } + sc.cm.findEntry(sc.pid).deleteChild(sc.id) + return true +} + +// deleteSelfFromMap checks whether it is valid to delete the subchannel from the map, which means +// deleting the subchannel from channelz's tracking entirely. Users can no longer use id to query +// the subchannel, and its memory will be garbage collected. +// +// The trace reference count of the subchannel must be 0 in order to be deleted from the map. This is +// specified in the channel tracing gRFC that as long as some other trace has reference to an entity, +// the trace of the referenced entity must not be deleted. In order to release the resource allocated +// by grpc, the reference to the grpc object is reset to a dummy object. +// +// deleteSelfFromMap must be called after deleteSelfFromTree returns true. +// +// It returns a bool to indicate whether the channel can be safely deleted from map. +func (sc *subChannel) deleteSelfFromMap() (delete bool) { + if sc.getTraceRefCount() != 0 { + // free the grpc struct (i.e. addrConn) + sc.c = &dummyChannel{} + return false + } + return true +} + +// deleteSelfIfReady tries to delete the subchannel itself from the channelz database. +// The delete process includes two steps: +// 1. delete the subchannel from the entry relation tree, i.e. delete the subchannel reference from +// its parent's child list. +// 2. delete the subchannel from the map, i.e. delete the subchannel entirely from channelz. Lookup +// by id will return entry not found error. +func (sc *subChannel) deleteSelfIfReady() { + if !sc.deleteSelfFromTree() { + return + } + if !sc.deleteSelfFromMap() { return } sc.cm.deleteEntry(sc.id) - sc.cm.findEntry(sc.pid).deleteChild(sc.id) + sc.trace.clear() +} + +func (sc *subChannel) getChannelTrace() *channelTrace { + return sc.trace +} + +func (sc *subChannel) incrTraceRefCount() { + atomic.AddInt32(&sc.traceRefCount, 1) +} + +func (sc *subChannel) decrTraceRefCount() { + atomic.AddInt32(&sc.traceRefCount, -1) +} + +func (sc *subChannel) getTraceRefCount() int { + i := atomic.LoadInt32(&sc.traceRefCount) + return int(i) +} + +func (sc *subChannel) getRefName() string { + return sc.refName } // SocketMetric defines the info channelz provides for a specific Socket, which @@ -281,9 +473,9 @@ type SocketInternalMetric struct { RemoteAddr net.Addr // Optional, represents the name of the remote endpoint, if different than // the original target name. - RemoteName string - //TODO: socket options - //TODO: Security + RemoteName string + SocketOptions *SocketOptionData + Security credentials.ChannelzSecurityValue } // Socket is the interface that should be satisfied in order to be tracked by @@ -317,6 +509,10 @@ func (ls *listenSocket) deleteSelfIfReady() { grpclog.Errorf("cannot call deleteSelfIfReady on a listen socket") } +func (ls *listenSocket) getParentID() int64 { + return ls.pid +} + type normalSocket struct { refName string s Socket @@ -342,6 +538,10 @@ func (ns *normalSocket) deleteSelfIfReady() { grpclog.Errorf("cannot call deleteSelfIfReady on a normal socket") } +func (ns *normalSocket) getParentID() int64 { + return ns.pid +} + // ServerMetric defines the info channelz provides for a specific Server, which // includes ServerInternalMetric and channelz-specific data, such as channelz id, // child list, etc. @@ -369,7 +569,6 @@ type ServerInternalMetric struct { CallsFailed int64 // The last time a call was started on the server. LastCallStartedTimestamp time.Time - //TODO: trace } // Server is the interface to be satisfied in order to be tracked by channelz as @@ -416,3 +615,88 @@ func (s *server) deleteSelfIfReady() { } s.cm.deleteEntry(s.id) } + +func (s *server) getParentID() int64 { + return 0 +} + +type tracedChannel interface { + getChannelTrace() *channelTrace + incrTraceRefCount() + decrTraceRefCount() + getRefName() string +} + +type channelTrace struct { + cm *channelMap + createdTime time.Time + eventCount int64 + mu sync.Mutex + events []*TraceEvent +} + +func (c *channelTrace) append(e *TraceEvent) { + c.mu.Lock() + if len(c.events) == getMaxTraceEntry() { + del := c.events[0] + c.events = c.events[1:] + if del.RefID != 0 { + // start recursive cleanup in a goroutine to not block the call originated from grpc. + go func() { + // need to acquire c.cm.mu lock to call the unlocked attemptCleanup func. + c.cm.mu.Lock() + c.cm.decrTraceRefCount(del.RefID) + c.cm.mu.Unlock() + }() + } + } + e.Timestamp = time.Now() + c.events = append(c.events, e) + c.eventCount++ + c.mu.Unlock() +} + +func (c *channelTrace) clear() { + c.mu.Lock() + for _, e := range c.events { + if e.RefID != 0 { + // caller should have already held the c.cm.mu lock. + c.cm.decrTraceRefCount(e.RefID) + } + } + c.mu.Unlock() +} + +// Severity is the severity level of a trace event. +// The canonical enumeration of all valid values is here: +// https://github.com/grpc/grpc-proto/blob/9b13d199cc0d4703c7ea26c9c330ba695866eb23/grpc/channelz/v1/channelz.proto#L126. +type Severity int + +const ( + // CtUNKNOWN indicates unknown severity of a trace event. + CtUNKNOWN Severity = iota + // CtINFO indicates info level severity of a trace event. + CtINFO + // CtWarning indicates warning level severity of a trace event. + CtWarning + // CtError indicates error level severity of a trace event. + CtError +) + +// RefChannelType is the type of the entity being referenced in a trace event. +type RefChannelType int + +const ( + // RefChannel indicates the referenced entity is a Channel. + RefChannel RefChannelType = iota + // RefSubChannel indicates the referenced entity is a SubChannel. + RefSubChannel +) + +func (c *channelTrace) dumpData() *ChannelTrace { + c.mu.Lock() + ct := &ChannelTrace{EventNum: c.eventCount, CreationTime: c.createdTime} + ct.Events = c.events[:len(c.events)] + c.mu.Unlock() + return ct +} diff --git a/vendor/google.golang.org/grpc/internal/channelz/types_linux.go b/vendor/google.golang.org/grpc/internal/channelz/types_linux.go new file mode 100644 index 0000000000000000000000000000000000000000..692dd6181778874569bbb31fa05d49da7a2d6e8b --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/channelz/types_linux.go @@ -0,0 +1,53 @@ +// +build !appengine + +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package channelz + +import ( + "syscall" + + "golang.org/x/sys/unix" +) + +// SocketOptionData defines the struct to hold socket option data, and related +// getter function to obtain info from fd. +type SocketOptionData struct { + Linger *unix.Linger + RecvTimeout *unix.Timeval + SendTimeout *unix.Timeval + TCPInfo *unix.TCPInfo +} + +// Getsockopt defines the function to get socket options requested by channelz. +// It is to be passed to syscall.RawConn.Control(). +func (s *SocketOptionData) Getsockopt(fd uintptr) { + if v, err := unix.GetsockoptLinger(int(fd), syscall.SOL_SOCKET, syscall.SO_LINGER); err == nil { + s.Linger = v + } + if v, err := unix.GetsockoptTimeval(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVTIMEO); err == nil { + s.RecvTimeout = v + } + if v, err := unix.GetsockoptTimeval(int(fd), syscall.SOL_SOCKET, syscall.SO_SNDTIMEO); err == nil { + s.SendTimeout = v + } + if v, err := unix.GetsockoptTCPInfo(int(fd), syscall.SOL_TCP, syscall.TCP_INFO); err == nil { + s.TCPInfo = v + } +} diff --git a/vendor/google.golang.org/grpc/internal/channelz/types_nonlinux.go b/vendor/google.golang.org/grpc/internal/channelz/types_nonlinux.go new file mode 100644 index 0000000000000000000000000000000000000000..79edbefc433182444b666b8a95e46a1d76c0ec84 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/channelz/types_nonlinux.go @@ -0,0 +1,44 @@ +// +build !linux appengine + +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package channelz + +import ( + "sync" + + "google.golang.org/grpc/grpclog" +) + +var once sync.Once + +// SocketOptionData defines the struct to hold socket option data, and related +// getter function to obtain info from fd. +// Windows OS doesn't support Socket Option +type SocketOptionData struct { +} + +// Getsockopt defines the function to get socket options requested by channelz. +// It is to be passed to syscall.RawConn.Control(). +// Windows OS doesn't support Socket Option +func (s *SocketOptionData) Getsockopt(fd uintptr) { + once.Do(func() { + grpclog.Warningln("Channelz: socket options are not supported on non-linux os and appengine.") + }) +} diff --git a/vendor/google.golang.org/grpc/credentials/credentials_util_go18.go b/vendor/google.golang.org/grpc/internal/channelz/util_linux.go similarity index 58% rename from vendor/google.golang.org/grpc/credentials/credentials_util_go18.go rename to vendor/google.golang.org/grpc/internal/channelz/util_linux.go index 93f0e1d8de23a5e934b1748179fadc0716fa40c6..fdf409d55de3b45fbc85805d9d01775bba382590 100644 --- a/vendor/google.golang.org/grpc/credentials/credentials_util_go18.go +++ b/vendor/google.golang.org/grpc/internal/channelz/util_linux.go @@ -1,8 +1,8 @@ -// +build go1.8 +// +build linux,!appengine /* * - * Copyright 2017 gRPC authors. + * Copyright 2018 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,21 +18,22 @@ * */ -package credentials +package channelz import ( - "crypto/tls" + "syscall" ) -// cloneTLSConfig returns a shallow clone of the exported -// fields of cfg, ignoring the unexported sync.Once, which -// contains a mutex and must not be copied. -// -// If cfg is nil, a new zero tls.Config is returned. -func cloneTLSConfig(cfg *tls.Config) *tls.Config { - if cfg == nil { - return &tls.Config{} +// GetSocketOption gets the socket option info of the conn. +func GetSocketOption(socket interface{}) *SocketOptionData { + c, ok := socket.(syscall.Conn) + if !ok { + return nil } - - return cfg.Clone() + data := &SocketOptionData{} + if rawConn, err := c.SyscallConn(); err == nil { + rawConn.Control(data.Getsockopt) + return data + } + return nil } diff --git a/vendor/google.golang.org/grpc/naming/go18.go b/vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go similarity index 73% rename from vendor/google.golang.org/grpc/naming/go18.go rename to vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go index b5a0f842748fc66d85df86f93f6224657611ff05..8864a081116421768e863235d1cb8e25b043710b 100644 --- a/vendor/google.golang.org/grpc/naming/go18.go +++ b/vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go @@ -1,8 +1,8 @@ -// +build go1.8 +// +build !linux appengine /* * - * Copyright 2017 gRPC authors. + * Copyright 2018 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,11 +18,9 @@ * */ -package naming +package channelz -import "net" - -var ( - lookupHost = net.DefaultResolver.LookupHost - lookupSRV = net.DefaultResolver.LookupSRV -) +// GetSocketOption gets the socket option info of the conn. +func GetSocketOption(c interface{}) *SocketOptionData { + return nil +} diff --git a/vendor/google.golang.org/grpc/internal/channelz/util_test.go b/vendor/google.golang.org/grpc/internal/channelz/util_test.go new file mode 100644 index 0000000000000000000000000000000000000000..6091e1a3e44ab9fe6d0ebed55022dfa462e1ef1d --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/channelz/util_test.go @@ -0,0 +1,90 @@ +// +build linux,go1.10,!appengine + +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// The test in this file should be run in an environment that has go1.10 or later, +// as the function SyscallConn() (required to get socket option) was introduced +// to net.TCPListener in go1.10. + +package channelz_test + +import ( + "net" + "reflect" + "syscall" + "testing" + + "golang.org/x/sys/unix" + "google.golang.org/grpc/internal/channelz" +) + +func TestGetSocketOpt(t *testing.T) { + network, addr := "tcp", ":0" + ln, err := net.Listen(network, addr) + if err != nil { + t.Fatalf("net.Listen(%s,%s) failed with err: %v", network, addr, err) + } + defer ln.Close() + go func() { + ln.Accept() + }() + conn, _ := net.Dial(network, ln.Addr().String()) + defer conn.Close() + tcpc := conn.(*net.TCPConn) + raw, err := tcpc.SyscallConn() + if err != nil { + t.Fatalf("SyscallConn() failed due to %v", err) + } + + l := &unix.Linger{Onoff: 1, Linger: 5} + recvTimout := &unix.Timeval{Sec: 100} + sendTimeout := &unix.Timeval{Sec: 8888} + raw.Control(func(fd uintptr) { + err := unix.SetsockoptLinger(int(fd), syscall.SOL_SOCKET, syscall.SO_LINGER, l) + if err != nil { + t.Fatalf("failed to SetsockoptLinger(%v,%v,%v,%v) due to %v", int(fd), syscall.SOL_SOCKET, syscall.SO_LINGER, l, err) + } + err = unix.SetsockoptTimeval(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, recvTimout) + if err != nil { + t.Fatalf("failed to SetsockoptTimeval(%v,%v,%v,%v) due to %v", int(fd), syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, recvTimout, err) + } + err = unix.SetsockoptTimeval(int(fd), syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, sendTimeout) + if err != nil { + t.Fatalf("failed to SetsockoptTimeval(%v,%v,%v,%v) due to %v", int(fd), syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, sendTimeout, err) + } + }) + sktopt := channelz.GetSocketOption(conn) + if !reflect.DeepEqual(sktopt.Linger, l) { + t.Fatalf("get socket option linger, want: %v, got %v", l, sktopt.Linger) + } + if !reflect.DeepEqual(sktopt.RecvTimeout, recvTimout) { + t.Logf("get socket option recv timeout, want: %v, got %v, may be caused by system allowing non or partial setting of this value", recvTimout, sktopt.RecvTimeout) + } + if !reflect.DeepEqual(sktopt.SendTimeout, sendTimeout) { + t.Logf("get socket option send timeout, want: %v, got %v, may be caused by system allowing non or partial setting of this value", sendTimeout, sktopt.SendTimeout) + } + if sktopt == nil || sktopt.TCPInfo != nil && sktopt.TCPInfo.State != 1 { + t.Fatalf("TCPInfo.State want 1 (TCP_ESTABLISHED), got %v", sktopt) + } + + sktopt = channelz.GetSocketOption(ln) + if sktopt == nil || sktopt.TCPInfo == nil || sktopt.TCPInfo.State != 10 { + t.Fatalf("TCPInfo.State want 10 (TCP_LISTEN), got %v", sktopt) + } +} diff --git a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go new file mode 100644 index 0000000000000000000000000000000000000000..a3e02b6619479b022a16065db12d0da4bc3403b3 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go @@ -0,0 +1,69 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package envconfig contains grpc settings configured by environment variables. +package envconfig + +import ( + "os" + "strings" +) + +const ( + prefix = "GRPC_GO_" + retryStr = prefix + "RETRY" + requireHandshakeStr = prefix + "REQUIRE_HANDSHAKE" +) + +// RequireHandshakeSetting describes the settings for handshaking. +type RequireHandshakeSetting int + +const ( + // RequireHandshakeHybrid (default, deprecated) indicates to wait for + // handshake before considering a connection ready, but wait before + // considering successful. + RequireHandshakeHybrid RequireHandshakeSetting = iota + // RequireHandshakeOn (default after the 1.17 release) indicates to wait + // for handshake before considering a connection ready/successful. + RequireHandshakeOn + // RequireHandshakeOff indicates to not wait for handshake before + // considering a connection ready/successful. + RequireHandshakeOff +) + +var ( + // Retry is set if retry is explicitly enabled via "GRPC_GO_RETRY=on". + Retry = strings.EqualFold(os.Getenv(retryStr), "on") + // RequireHandshake is set based upon the GRPC_GO_REQUIRE_HANDSHAKE + // environment variable. + // + // Will be removed after the 1.18 release. + RequireHandshake RequireHandshakeSetting +) + +func init() { + switch strings.ToLower(os.Getenv(requireHandshakeStr)) { + case "on": + RequireHandshake = RequireHandshakeOn + case "off": + RequireHandshake = RequireHandshakeOff + case "hybrid": + // Will be removed after the 1.17 release. + RequireHandshake = RequireHandshakeHybrid + } +} diff --git a/vendor/google.golang.org/grpc/internal/grpcsync/event.go b/vendor/google.golang.org/grpc/internal/grpcsync/event.go new file mode 100644 index 0000000000000000000000000000000000000000..fbe697c37684c3981be2fb18c03a4c2a371f4c7b --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/grpcsync/event.go @@ -0,0 +1,61 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package grpcsync implements additional synchronization primitives built upon +// the sync package. +package grpcsync + +import ( + "sync" + "sync/atomic" +) + +// Event represents a one-time event that may occur in the future. +type Event struct { + fired int32 + c chan struct{} + o sync.Once +} + +// Fire causes e to complete. It is safe to call multiple times, and +// concurrently. It returns true iff this call to Fire caused the signaling +// channel returned by Done to close. +func (e *Event) Fire() bool { + ret := false + e.o.Do(func() { + atomic.StoreInt32(&e.fired, 1) + close(e.c) + ret = true + }) + return ret +} + +// Done returns a channel that will be closed when Fire is called. +func (e *Event) Done() <-chan struct{} { + return e.c +} + +// HasFired returns true if Fire has been called. +func (e *Event) HasFired() bool { + return atomic.LoadInt32(&e.fired) == 1 +} + +// NewEvent returns a new, ready-to-use Event. +func NewEvent() *Event { + return &Event{c: make(chan struct{})} +} diff --git a/vendor/google.golang.org/grpc/internal/grpcsync/event_test.go b/vendor/google.golang.org/grpc/internal/grpcsync/event_test.go new file mode 100644 index 0000000000000000000000000000000000000000..af64d1830528fbf142fe2c9d008a4aa20c3eec02 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/grpcsync/event_test.go @@ -0,0 +1,69 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package grpcsync + +import "testing" + +func TestEventHasFired(t *testing.T) { + e := NewEvent() + if e.HasFired() { + t.Fatal("e.HasFired() = true; want false") + } + if !e.Fire() { + t.Fatal("e.Fire() = false; want true") + } + if !e.HasFired() { + t.Fatal("e.HasFired() = false; want true") + } +} + +func TestEventDoneChannel(t *testing.T) { + e := NewEvent() + select { + case <-e.Done(): + t.Fatal("e.HasFired() = true; want false") + default: + } + if !e.Fire() { + t.Fatal("e.Fire() = false; want true") + } + select { + case <-e.Done(): + default: + t.Fatal("e.HasFired() = false; want true") + } +} + +func TestEventMultipleFires(t *testing.T) { + e := NewEvent() + if e.HasFired() { + t.Fatal("e.HasFired() = true; want false") + } + if !e.Fire() { + t.Fatal("e.Fire() = false; want true") + } + for i := 0; i < 3; i++ { + if !e.HasFired() { + t.Fatal("e.HasFired() = false; want true") + } + if e.Fire() { + t.Fatal("e.Fire() = true; want false") + } + } +} diff --git a/vendor/google.golang.org/grpc/internal/internal.go b/vendor/google.golang.org/grpc/internal/internal.go index cd34267f7f304b4daf76343f14cbcb566cd9b51c..f8932b1d86aab7348d71c0ea95dcbd907bc361c3 100644 --- a/vendor/google.golang.org/grpc/internal/internal.go +++ b/vendor/google.golang.org/grpc/internal/internal.go @@ -20,17 +20,24 @@ // symbols to avoid circular dependencies. package internal -var ( - - // TestingUseHandlerImpl enables the http.Handler-based server implementation. - // It must be called before Serve and requires TLS credentials. - // - // The provided grpcServer must be of type *grpc.Server. It is untyped - // for circular dependency reasons. - TestingUseHandlerImpl func(grpcServer interface{}) +import "context" +var ( // WithContextDialer is exported by clientconn.go WithContextDialer interface{} // func(context.Context, string) (net.Conn, error) grpc.DialOption // WithResolverBuilder is exported by clientconn.go WithResolverBuilder interface{} // func (resolver.Builder) grpc.DialOption + // HealthCheckFunc is used to provide client-side LB channel health checking + HealthCheckFunc func(ctx context.Context, newStream func() (interface{}, error), reportHealth func(bool), serviceName string) error +) + +const ( + // CredsBundleModeFallback switches GoogleDefaultCreds to fallback mode. + CredsBundleModeFallback = "fallback" + // CredsBundleModeBalancer switches GoogleDefaultCreds to grpclb balancer + // mode. + CredsBundleModeBalancer = "balancer" + // CredsBundleModeBackendFromBalancer switches GoogleDefaultCreds to mode + // that supports backend returned by grpclb balancer. + CredsBundleModeBackendFromBalancer = "backend-from-balancer" ) diff --git a/vendor/google.golang.org/grpc/internal/syscall/syscall_linux.go b/vendor/google.golang.org/grpc/internal/syscall/syscall_linux.go new file mode 100644 index 0000000000000000000000000000000000000000..43281a3e078db1af11c37a22c59e745dc9f67ca8 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/syscall/syscall_linux.go @@ -0,0 +1,114 @@ +// +build !appengine + +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package syscall provides functionalities that grpc uses to get low-level operating system +// stats/info. +package syscall + +import ( + "fmt" + "net" + "syscall" + "time" + + "golang.org/x/sys/unix" + "google.golang.org/grpc/grpclog" +) + +// GetCPUTime returns the how much CPU time has passed since the start of this process. +func GetCPUTime() int64 { + var ts unix.Timespec + if err := unix.ClockGettime(unix.CLOCK_PROCESS_CPUTIME_ID, &ts); err != nil { + grpclog.Fatal(err) + } + return ts.Nano() +} + +// Rusage is an alias for syscall.Rusage under linux non-appengine environment. +type Rusage syscall.Rusage + +// GetRusage returns the resource usage of current process. +func GetRusage() (rusage *Rusage) { + rusage = new(Rusage) + syscall.Getrusage(syscall.RUSAGE_SELF, (*syscall.Rusage)(rusage)) + return +} + +// CPUTimeDiff returns the differences of user CPU time and system CPU time used +// between two Rusage structs. +func CPUTimeDiff(first *Rusage, latest *Rusage) (float64, float64) { + f := (*syscall.Rusage)(first) + l := (*syscall.Rusage)(latest) + var ( + utimeDiffs = l.Utime.Sec - f.Utime.Sec + utimeDiffus = l.Utime.Usec - f.Utime.Usec + stimeDiffs = l.Stime.Sec - f.Stime.Sec + stimeDiffus = l.Stime.Usec - f.Stime.Usec + ) + + uTimeElapsed := float64(utimeDiffs) + float64(utimeDiffus)*1.0e-6 + sTimeElapsed := float64(stimeDiffs) + float64(stimeDiffus)*1.0e-6 + + return uTimeElapsed, sTimeElapsed +} + +// SetTCPUserTimeout sets the TCP user timeout on a connection's socket +func SetTCPUserTimeout(conn net.Conn, timeout time.Duration) error { + tcpconn, ok := conn.(*net.TCPConn) + if !ok { + // not a TCP connection. exit early + return nil + } + rawConn, err := tcpconn.SyscallConn() + if err != nil { + return fmt.Errorf("error getting raw connection: %v", err) + } + err = rawConn.Control(func(fd uintptr) { + err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT, int(timeout/time.Millisecond)) + }) + if err != nil { + return fmt.Errorf("error setting option on socket: %v", err) + } + + return nil +} + +// GetTCPUserTimeout gets the TCP user timeout on a connection's socket +func GetTCPUserTimeout(conn net.Conn) (opt int, err error) { + tcpconn, ok := conn.(*net.TCPConn) + if !ok { + err = fmt.Errorf("conn is not *net.TCPConn. got %T", conn) + return + } + rawConn, err := tcpconn.SyscallConn() + if err != nil { + err = fmt.Errorf("error getting raw connection: %v", err) + return + } + err = rawConn.Control(func(fd uintptr) { + opt, err = syscall.GetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT) + }) + if err != nil { + err = fmt.Errorf("error getting option on socket: %v", err) + return + } + + return +} diff --git a/vendor/google.golang.org/grpc/internal/syscall/syscall_nonlinux.go b/vendor/google.golang.org/grpc/internal/syscall/syscall_nonlinux.go new file mode 100644 index 0000000000000000000000000000000000000000..61678feb00443b8d73fb4873f0a62894a061d81a --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/syscall/syscall_nonlinux.go @@ -0,0 +1,63 @@ +// +build !linux appengine + +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package syscall + +import ( + "net" + "time" + + "google.golang.org/grpc/grpclog" +) + +func init() { + grpclog.Info("CPU time info is unavailable on non-linux or appengine environment.") +} + +// GetCPUTime returns the how much CPU time has passed since the start of this process. +// It always returns 0 under non-linux or appengine environment. +func GetCPUTime() int64 { + return 0 +} + +// Rusage is an empty struct under non-linux or appengine environment. +type Rusage struct{} + +// GetRusage is a no-op function under non-linux or appengine environment. +func GetRusage() (rusage *Rusage) { + return nil +} + +// CPUTimeDiff returns the differences of user CPU time and system CPU time used +// between two Rusage structs. It a no-op function for non-linux or appengine environment. +func CPUTimeDiff(first *Rusage, latest *Rusage) (float64, float64) { + return 0, 0 +} + +// SetTCPUserTimeout is a no-op function under non-linux or appengine environments +func SetTCPUserTimeout(conn net.Conn, timeout time.Duration) error { + return nil +} + +// GetTCPUserTimeout is a no-op function under non-linux or appengine environments +// a negative return value indicates the operation is not supported +func GetTCPUserTimeout(conn net.Conn) (int, error) { + return -1, nil +} diff --git a/vendor/google.golang.org/grpc/internal/testutils/pipe_listener.go b/vendor/google.golang.org/grpc/internal/testutils/pipe_listener.go new file mode 100644 index 0000000000000000000000000000000000000000..6bd3bc0bea126cba9b40e4ad9b58f624487b5daf --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/testutils/pipe_listener.go @@ -0,0 +1,96 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package testutils contains testing helpers. +package testutils + +import ( + "errors" + "net" + "time" +) + +var errClosed = errors.New("closed") + +type pipeAddr struct{} + +func (p pipeAddr) Network() string { return "pipe" } +func (p pipeAddr) String() string { return "pipe" } + +// PipeListener is a listener with an unbuffered pipe. Each write will complete only once the other side reads. It +// should only be created using NewPipeListener. +type PipeListener struct { + c chan chan<- net.Conn + done chan struct{} +} + +// NewPipeListener creates a new pipe listener. +func NewPipeListener() *PipeListener { + return &PipeListener{ + c: make(chan chan<- net.Conn), + done: make(chan struct{}), + } +} + +// Accept accepts a connection. +func (p *PipeListener) Accept() (net.Conn, error) { + var connChan chan<- net.Conn + select { + case <-p.done: + return nil, errClosed + case connChan = <-p.c: + select { + case <-p.done: + close(connChan) + return nil, errClosed + default: + } + } + c1, c2 := net.Pipe() + connChan <- c1 + close(connChan) + return c2, nil +} + +// Close closes the listener. +func (p *PipeListener) Close() error { + close(p.done) + return nil +} + +// Addr returns a pipe addr. +func (p *PipeListener) Addr() net.Addr { + return pipeAddr{} +} + +// Dialer dials a connection. +func (p *PipeListener) Dialer() func(string, time.Duration) (net.Conn, error) { + return func(string, time.Duration) (net.Conn, error) { + connChan := make(chan net.Conn) + select { + case p.c <- connChan: + case <-p.done: + return nil, errClosed + } + conn, ok := <-connChan + if !ok { + return nil, errClosed + } + return conn, nil + } +} diff --git a/vendor/google.golang.org/grpc/internal/testutils/pipe_listener_test.go b/vendor/google.golang.org/grpc/internal/testutils/pipe_listener_test.go new file mode 100644 index 0000000000000000000000000000000000000000..9bd399cb0be460069ef3f6515106e6f4702cdbbe --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/testutils/pipe_listener_test.go @@ -0,0 +1,163 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package testutils_test + +import ( + "testing" + "time" + + "google.golang.org/grpc/internal/testutils" +) + +func TestPipeListener(t *testing.T) { + pl := testutils.NewPipeListener() + recvdBytes := make(chan []byte) + const want = "hello world" + + go func() { + c, err := pl.Accept() + if err != nil { + t.Error(err) + } + + read := make([]byte, len(want)) + _, err = c.Read(read) + if err != nil { + t.Error(err) + } + recvdBytes <- read + }() + + dl := pl.Dialer() + conn, err := dl("", time.Duration(0)) + if err != nil { + t.Fatal(err) + } + + _, err = conn.Write([]byte(want)) + if err != nil { + t.Fatal(err) + } + + select { + case gotBytes := <-recvdBytes: + got := string(gotBytes) + if got != want { + t.Fatalf("expected to get %s, got %s", got, want) + } + case <-time.After(100 * time.Millisecond): + t.Fatal("timed out waiting for server to receive bytes") + } +} + +func TestUnblocking(t *testing.T) { + for _, test := range []struct { + desc string + blockFuncShouldError bool + blockFunc func(*testutils.PipeListener, chan struct{}) error + unblockFunc func(*testutils.PipeListener) error + }{ + { + desc: "Accept unblocks Dial", + blockFunc: func(pl *testutils.PipeListener, done chan struct{}) error { + dl := pl.Dialer() + _, err := dl("", time.Duration(0)) + close(done) + return err + }, + unblockFunc: func(pl *testutils.PipeListener) error { + _, err := pl.Accept() + return err + }, + }, + { + desc: "Close unblocks Dial", + blockFuncShouldError: true, // because pl.Close will be called + blockFunc: func(pl *testutils.PipeListener, done chan struct{}) error { + dl := pl.Dialer() + _, err := dl("", time.Duration(0)) + close(done) + return err + }, + unblockFunc: func(pl *testutils.PipeListener) error { + return pl.Close() + }, + }, + { + desc: "Dial unblocks Accept", + blockFunc: func(pl *testutils.PipeListener, done chan struct{}) error { + _, err := pl.Accept() + close(done) + return err + }, + unblockFunc: func(pl *testutils.PipeListener) error { + dl := pl.Dialer() + _, err := dl("", time.Duration(0)) + return err + }, + }, + { + desc: "Close unblocks Accept", + blockFuncShouldError: true, // because pl.Close will be called + blockFunc: func(pl *testutils.PipeListener, done chan struct{}) error { + _, err := pl.Accept() + close(done) + return err + }, + unblockFunc: func(pl *testutils.PipeListener) error { + return pl.Close() + }, + }, + } { + t.Log(test.desc) + testUnblocking(t, test.blockFunc, test.unblockFunc, test.blockFuncShouldError) + } +} + +func testUnblocking(t *testing.T, blockFunc func(*testutils.PipeListener, chan struct{}) error, unblockFunc func(*testutils.PipeListener) error, blockFuncShouldError bool) { + pl := testutils.NewPipeListener() + dialFinished := make(chan struct{}) + + go func() { + err := blockFunc(pl, dialFinished) + if blockFuncShouldError && err == nil { + t.Error("expected blocking func to return error because pl.Close was called, but got nil") + } + + if !blockFuncShouldError && err != nil { + t.Error(err) + } + }() + + select { + case <-dialFinished: + t.Fatal("expected Dial to block until pl.Close or pl.Accept") + default: + } + + if err := unblockFunc(pl); err != nil { + t.Fatal(err) + } + + select { + case <-dialFinished: + case <-time.After(100 * time.Millisecond): + t.Fatal("expected Accept to unblock after pl.Accept was called") + } +} diff --git a/vendor/google.golang.org/grpc/transport/bdp_estimator.go b/vendor/google.golang.org/grpc/internal/transport/bdp_estimator.go similarity index 94% rename from vendor/google.golang.org/grpc/transport/bdp_estimator.go rename to vendor/google.golang.org/grpc/internal/transport/bdp_estimator.go index 63cd2627c87aa74e1ca1681b485fccbd775e3e78..070680edbac1271bda40a5cb99bc61789fef7887 100644 --- a/vendor/google.golang.org/grpc/transport/bdp_estimator.go +++ b/vendor/google.golang.org/grpc/internal/transport/bdp_estimator.go @@ -24,9 +24,10 @@ import ( ) const ( - // bdpLimit is the maximum value the flow control windows - // will be increased to. - bdpLimit = (1 << 20) * 4 + // bdpLimit is the maximum value the flow control windows will be increased + // to. TCP typically limits this to 4MB, but some systems go up to 16MB. + // Since this is only a limit, it is safe to make it optimistic. + bdpLimit = (1 << 20) * 16 // alpha is a constant factor used to keep a moving average // of RTTs. alpha = 0.9 diff --git a/vendor/google.golang.org/grpc/transport/controlbuf.go b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go similarity index 81% rename from vendor/google.golang.org/grpc/transport/controlbuf.go rename to vendor/google.golang.org/grpc/internal/transport/controlbuf.go index 5c5891a11bfe2a8fe72018536b7cfc582b1d545a..204ba1588bbfd5a0c6902e32a73a6fab32e9fcc3 100644 --- a/vendor/google.golang.org/grpc/transport/controlbuf.go +++ b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go @@ -104,7 +104,6 @@ type headerFrame struct { type cleanupStream struct { streamID uint32 - idPtr *uint32 rst bool rstCode http2.ErrCode onWrite func() @@ -138,9 +137,6 @@ type outgoingSettings struct { ss []http2.Setting } -type settingsAck struct { -} - type incomingGoAway struct { } @@ -229,6 +225,12 @@ func (l *outStreamList) dequeue() *outStream { return b } +// controlBuffer is a way to pass information to loopy. +// Information is passed as specific struct types called control frames. +// A control frame not only represents data, messages or headers to be sent out +// but can also be used to instruct loopy to update its internal state. +// It shouldn't be confused with an HTTP2 frame, although some of the control frames +// like dataFrame and headerFrame do go out on wire as HTTP2 frames. type controlBuffer struct { ch chan struct{} done <-chan struct{} @@ -279,6 +281,21 @@ func (c *controlBuffer) executeAndPut(f func(it interface{}) bool, it interface{ return true, nil } +// Note argument f should never be nil. +func (c *controlBuffer) execute(f func(it interface{}) bool, it interface{}) (bool, error) { + c.mu.Lock() + if c.err != nil { + c.mu.Unlock() + return false, c.err + } + if !f(it) { // f wasn't successful + c.mu.Unlock() + return false, nil + } + c.mu.Unlock() + return true, nil +} + func (c *controlBuffer) get(block bool) (interface{}, error) { for { c.mu.Lock() @@ -335,13 +352,29 @@ const ( serverSide ) +// Loopy receives frames from the control buffer. +// Each frame is handled individually; most of the work done by loopy goes +// into handling data frames. Loopy maintains a queue of active streams, and each +// stream maintains a queue of data frames; as loopy receives data frames +// it gets added to the queue of the relevant stream. +// Loopy goes over this list of active streams by processing one node every iteration, +// thereby closely resemebling to a round-robin scheduling over all streams. While +// processing a stream, loopy writes out data bytes from this stream capped by the min +// of http2MaxFrameLen, connection-level flow control and stream-level flow control. type loopyWriter struct { - side side - cbuf *controlBuffer - sendQuota uint32 - oiws uint32 // outbound initial window size. - estdStreams map[uint32]*outStream // Established streams. - activeStreams *outStreamList // Streams that are sending data. + side side + cbuf *controlBuffer + sendQuota uint32 + oiws uint32 // outbound initial window size. + // estdStreams is map of all established streams that are not cleaned-up yet. + // On client-side, this is all streams whose headers were sent out. + // On server-side, this is all streams whose headers were received. + estdStreams map[uint32]*outStream // Established streams. + // activeStreams is a linked-list of all streams that have data to send and some + // stream-level flow control quota. + // Each of these streams internally have a list of data items(and perhaps trailers + // on the server-side) to be sent out. + activeStreams *outStreamList framer *framer hBuf *bytes.Buffer // The buffer for HPACK encoding. hEnc *hpack.Encoder // HPACK encoder. @@ -372,6 +405,21 @@ func newLoopyWriter(s side, fr *framer, cbuf *controlBuffer, bdpEst *bdpEstimato const minBatchSize = 1000 // run should be run in a separate goroutine. +// It reads control frames from controlBuf and processes them by: +// 1. Updating loopy's internal state, or/and +// 2. Writing out HTTP2 frames on the wire. +// +// Loopy keeps all active streams with data to send in a linked-list. +// All streams in the activeStreams linked-list must have both: +// 1. Data to send, and +// 2. Stream level flow control quota available. +// +// In each iteration of run loop, other than processing the incoming control +// frame, loopy calls processData, which processes one node from the activeStreams linked-list. +// This results in writing of HTTP2 frames into an underlying write buffer. +// When there's no more control frames to read from controlBuf, loopy flushes the write buffer. +// As an optimization, to increase the batch size for each flush, loopy yields the processor, once +// if the batch size is too low to give stream goroutines a chance to fill it up. func (l *loopyWriter) run() (err error) { defer func() { if err == ErrConnClosing { @@ -696,21 +744,30 @@ func (l *loopyWriter) applySettings(ss []http2.Setting) error { return nil } +// processData removes the first stream from active streams, writes out at most 16KB +// of its data and then puts it at the end of activeStreams if there's still more data +// to be sent and stream has some stream-level flow control. func (l *loopyWriter) processData() (bool, error) { if l.sendQuota == 0 { return true, nil } - str := l.activeStreams.dequeue() + str := l.activeStreams.dequeue() // Remove the first stream. if str == nil { return true, nil } - dataItem := str.itl.peek().(*dataFrame) - if len(dataItem.h) == 0 && len(dataItem.d) == 0 { + dataItem := str.itl.peek().(*dataFrame) // Peek at the first data item this stream. + // A data item is represented by a dataFrame, since it later translates into + // multiple HTTP2 data frames. + // Every dataFrame has two buffers; h that keeps grpc-message header and d that is acutal data. + // As an optimization to keep wire traffic low, data from d is copied to h to make as big as the + // maximum possilbe HTTP2 frame size. + + if len(dataItem.h) == 0 && len(dataItem.d) == 0 { // Empty data frame // Client sends out empty data frame with endStream = true if err := l.framer.fr.WriteData(dataItem.streamID, dataItem.endStream, nil); err != nil { return false, err } - str.itl.dequeue() + str.itl.dequeue() // remove the empty data item from stream if str.itl.isEmpty() { str.state = empty } else if trailer, ok := str.itl.peek().(*headerFrame); ok { // the next item is trailers. @@ -739,21 +796,20 @@ func (l *loopyWriter) processData() (bool, error) { if len(buf) < size { size = len(buf) } - if strQuota := int(l.oiws) - str.bytesOutStanding; strQuota <= 0 { + if strQuota := int(l.oiws) - str.bytesOutStanding; strQuota <= 0 { // stream-level flow control. str.state = waitingOnStreamQuota return false, nil } else if strQuota < size { size = strQuota } - if l.sendQuota < uint32(size) { + if l.sendQuota < uint32(size) { // connection-level flow control. size = int(l.sendQuota) } // Now that outgoing flow controls are checked we can replenish str's write quota str.wq.replenish(size) var endStream bool - // This last data message on this stream and all - // of it can be written in this go. + // If this is the last data message on this stream and all of it can be written in this iteration. if dataItem.endStream && size == len(buf) { // buf contains either data or it contains header but data is empty. if idx == 1 || len(dataItem.d) == 0 { diff --git a/vendor/google.golang.org/grpc/internal/transport/defaults.go b/vendor/google.golang.org/grpc/internal/transport/defaults.go new file mode 100644 index 0000000000000000000000000000000000000000..9fa306b2e07a20b8f31e990c186726abe67d6776 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/transport/defaults.go @@ -0,0 +1,49 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package transport + +import ( + "math" + "time" +) + +const ( + // The default value of flow control window size in HTTP2 spec. + defaultWindowSize = 65535 + // The initial window size for flow control. + initialWindowSize = defaultWindowSize // for an RPC + infinity = time.Duration(math.MaxInt64) + defaultClientKeepaliveTime = infinity + defaultClientKeepaliveTimeout = 20 * time.Second + defaultMaxStreamsClient = 100 + defaultMaxConnectionIdle = infinity + defaultMaxConnectionAge = infinity + defaultMaxConnectionAgeGrace = infinity + defaultServerKeepaliveTime = 2 * time.Hour + defaultServerKeepaliveTimeout = 20 * time.Second + defaultKeepalivePolicyMinTime = 5 * time.Minute + // max window limit set by HTTP2 Specs. + maxWindowSize = math.MaxInt32 + // defaultWriteQuota is the default value for number of data + // bytes that each stream can schedule before some of it being + // flushed out. + defaultWriteQuota = 64 * 1024 + defaultClientMaxHeaderListSize = uint32(16 << 20) + defaultServerMaxHeaderListSize = uint32(16 << 20) +) diff --git a/vendor/google.golang.org/grpc/transport/flowcontrol.go b/vendor/google.golang.org/grpc/internal/transport/flowcontrol.go similarity index 86% rename from vendor/google.golang.org/grpc/transport/flowcontrol.go rename to vendor/google.golang.org/grpc/internal/transport/flowcontrol.go index bbf98b6f5eebbf0779b182ddf363eb7a1b0ab4e9..5ea997a7e45b0fcd5e2086ceb76bfa47ddf6a61e 100644 --- a/vendor/google.golang.org/grpc/transport/flowcontrol.go +++ b/vendor/google.golang.org/grpc/internal/transport/flowcontrol.go @@ -23,30 +23,6 @@ import ( "math" "sync" "sync/atomic" - "time" -) - -const ( - // The default value of flow control window size in HTTP2 spec. - defaultWindowSize = 65535 - // The initial window size for flow control. - initialWindowSize = defaultWindowSize // for an RPC - infinity = time.Duration(math.MaxInt64) - defaultClientKeepaliveTime = infinity - defaultClientKeepaliveTimeout = 20 * time.Second - defaultMaxStreamsClient = 100 - defaultMaxConnectionIdle = infinity - defaultMaxConnectionAge = infinity - defaultMaxConnectionAgeGrace = infinity - defaultServerKeepaliveTime = 2 * time.Hour - defaultServerKeepaliveTimeout = 20 * time.Second - defaultKeepalivePolicyMinTime = 5 * time.Minute - // max window limit set by HTTP2 Specs. - maxWindowSize = math.MaxInt32 - // defaultWriteQuota is the default value for number of data - // bytes that each stream can schedule before some of it being - // flushed out. - defaultWriteQuota = 64 * 1024 ) // writeQuota is a soft limit on the amount of data a stream can diff --git a/vendor/google.golang.org/grpc/transport/handler_server.go b/vendor/google.golang.org/grpc/internal/transport/handler_server.go similarity index 96% rename from vendor/google.golang.org/grpc/transport/handler_server.go rename to vendor/google.golang.org/grpc/internal/transport/handler_server.go index f71b74821749b34d3c65bc03a1ee5f2bf7ec2d40..73b41ea7e0b0fff4b18b817e9ffc7127ad725dfd 100644 --- a/vendor/google.golang.org/grpc/transport/handler_server.go +++ b/vendor/google.golang.org/grpc/internal/transport/handler_server.go @@ -24,6 +24,7 @@ package transport import ( + "context" "errors" "fmt" "io" @@ -34,7 +35,6 @@ import ( "time" "github.com/golang/protobuf/proto" - "golang.org/x/net/context" "golang.org/x/net/http2" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" @@ -80,7 +80,7 @@ func NewServerHandlerTransport(w http.ResponseWriter, r *http.Request, stats sta if v := r.Header.Get("grpc-timeout"); v != "" { to, err := decodeTimeout(v) if err != nil { - return nil, streamErrorf(codes.Internal, "malformed time-out: %v", err) + return nil, status.Errorf(codes.Internal, "malformed time-out: %v", err) } st.timeoutSet = true st.timeout = to @@ -98,7 +98,7 @@ func NewServerHandlerTransport(w http.ResponseWriter, r *http.Request, stats sta for _, v := range vv { v, err := decodeMetadataHeader(k, v) if err != nil { - return nil, streamErrorf(codes.Internal, "malformed binary metadata: %v", err) + return nil, status.Errorf(codes.Internal, "malformed binary metadata: %v", err) } metakv = append(metakv, k, v) } @@ -237,9 +237,9 @@ func (ht *serverHandlerTransport) WriteStatus(s *Stream, st *status.Status) erro if ht.stats != nil { ht.stats.HandleRPC(s.Context(), &stats.OutTrailer{}) } - ht.Close() close(ht.writes) } + ht.Close() return err } @@ -274,9 +274,7 @@ func (ht *serverHandlerTransport) Write(s *Stream, hdr []byte, data []byte, opts ht.writeCommonHeaders(s) ht.rw.Write(hdr) ht.rw.Write(data) - if !opts.Delay { - ht.rw.(http.Flusher).Flush() - } + ht.rw.(http.Flusher).Flush() }) } @@ -309,7 +307,7 @@ func (ht *serverHandlerTransport) WriteHeader(s *Stream, md metadata.MD) error { func (ht *serverHandlerTransport) HandleStreams(startStream func(*Stream), traceCtx func(context.Context, string) context.Context) { // With this transport type there will be exactly 1 stream: this HTTP request. - ctx := contextFromRequest(ht.req) + ctx := ht.req.Context() var cancel context.CancelFunc if ht.timeoutSet { ctx, cancel = context.WithTimeout(ctx, ht.timeout) @@ -328,11 +326,11 @@ func (ht *serverHandlerTransport) HandleStreams(startStream func(*Stream), trace go func() { select { case <-requestOver: - return case <-ht.closedCh: case <-clientGone: } cancel() + ht.Close() }() req := ht.req @@ -434,18 +432,18 @@ func (ht *serverHandlerTransport) Drain() { // * io.EOF // * io.ErrUnexpectedEOF // * of type transport.ConnectionError -// * of type transport.StreamError +// * an error from the status package func mapRecvMsgError(err error) error { if err == io.EOF || err == io.ErrUnexpectedEOF { return err } if se, ok := err.(http2.StreamError); ok { if code, ok := http2ErrConvTab[se.Code]; ok { - return StreamError{ - Code: code, - Desc: se.Error(), - } + return status.Error(code, se.Error()) } } + if strings.Contains(err.Error(), "body closed by handler") { + return status.Error(codes.Canceled, err.Error()) + } return connectionErrorf(true, err, err.Error()) } diff --git a/vendor/google.golang.org/grpc/transport/handler_server_test.go b/vendor/google.golang.org/grpc/internal/transport/handler_server_test.go similarity index 98% rename from vendor/google.golang.org/grpc/transport/handler_server_test.go rename to vendor/google.golang.org/grpc/internal/transport/handler_server_test.go index 3261b8e3d204527520af3157c76d135f56c7515a..cf989c76e96a575c7e393cf55f4a60b8444aa151 100644 --- a/vendor/google.golang.org/grpc/transport/handler_server_test.go +++ b/vendor/google.golang.org/grpc/internal/transport/handler_server_test.go @@ -19,6 +19,7 @@ package transport import ( + "context" "errors" "fmt" "io" @@ -32,7 +33,6 @@ import ( "github.com/golang/protobuf/proto" dpb "github.com/golang/protobuf/ptypes/duration" - "golang.org/x/net/context" epb "google.golang.org/genproto/googleapis/rpc/errdetails" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" @@ -179,7 +179,7 @@ func TestHandlerTransport_NewServerHandlerTransport(t *testing.T) { }, RequestURI: "/service/foo.bar", }, - wantErr: `stream error: code = Internal desc = "malformed time-out: transport: timeout unit is not recognized: \"tomorrow\""`, + wantErr: `rpc error: code = Internal desc = malformed time-out: transport: timeout unit is not recognized: "tomorrow"`, }, { name: "with metadata", @@ -220,7 +220,7 @@ func TestHandlerTransport_NewServerHandlerTransport(t *testing.T) { } got, gotErr := NewServerHandlerTransport(rw, tt.req, nil) if (gotErr != nil) != (tt.wantErr != "") || (gotErr != nil && gotErr.Error() != tt.wantErr) { - t.Errorf("%s: error = %v; want %q", tt.name, gotErr, tt.wantErr) + t.Errorf("%s: error = %q; want %q", tt.name, gotErr.Error(), tt.wantErr) continue } if gotErr != nil { @@ -252,7 +252,6 @@ func newTestHandlerResponseWriter() http.ResponseWriter { type handleStreamTest struct { t *testing.T bodyw *io.PipeWriter - req *http.Request rw testHandlerResponseWriter ht *serverHandlerTransport } diff --git a/vendor/google.golang.org/grpc/transport/http2_client.go b/vendor/google.golang.org/grpc/internal/transport/http2_client.go similarity index 82% rename from vendor/google.golang.org/grpc/transport/http2_client.go rename to vendor/google.golang.org/grpc/internal/transport/http2_client.go index eaf007eb0ae469a3600260a005260e1040674f8d..39208b146e093d343aefae2401334b2264ca903c 100644 --- a/vendor/google.golang.org/grpc/transport/http2_client.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_client.go @@ -19,21 +19,24 @@ package transport import ( + "context" + "fmt" "io" "math" "net" + "strconv" "strings" "sync" "sync/atomic" "time" - "golang.org/x/net/context" "golang.org/x/net/http2" "golang.org/x/net/http2/hpack" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/internal/channelz" + "google.golang.org/grpc/internal/syscall" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" @@ -72,7 +75,7 @@ type http2Client struct { isSecure bool - creds []credentials.PerRPCCredentials + perRPCCreds []credentials.PerRPCCredentials // Boolean to keep track of reading activity on transport. // 1 is true and 0 is false. @@ -84,6 +87,9 @@ type http2Client struct { initialWindowSize int32 + // configured by peer through SETTINGS_MAX_HEADER_LIST_SIZE + maxSendHeaderListSize *uint32 + bdpEst *bdpEstimator // onSuccess is a callback that client transport calls upon // receiving server preface to signal that a succefull HTTP2 @@ -107,26 +113,17 @@ type http2Client struct { // Fields below are for channelz metric collection. channelzID int64 // channelz unique identification number - czmu sync.RWMutex - kpCount int64 - // The number of streams that have started, including already finished ones. - streamsStarted int64 - // The number of streams that have ended successfully by receiving EoS bit set - // frame from server. - streamsSucceeded int64 - streamsFailed int64 - lastStreamCreated time.Time - msgSent int64 - msgRecv int64 - lastMsgSent time.Time - lastMsgRecv time.Time + czData *channelzData + + onGoAway func(GoAwayReason) + onClose func() } func dial(ctx context.Context, fn func(context.Context, string) (net.Conn, error), addr string) (net.Conn, error) { if fn != nil { return fn(ctx, addr) } - return dialContext(ctx, "tcp", addr) + return (&net.Dialer{}).DialContext(ctx, "tcp", addr) } func isTemporary(err error) bool { @@ -148,7 +145,7 @@ func isTemporary(err error) bool { // newHTTP2Client constructs a connected ClientTransport to addr based on HTTP2 // and starts to receive messages on it. Non-nil error returns if construction // fails. -func newHTTP2Client(connectCtx, ctx context.Context, addr TargetInfo, opts ConnectOptions, onSuccess func()) (_ ClientTransport, err error) { +func newHTTP2Client(connectCtx, ctx context.Context, addr TargetInfo, opts ConnectOptions, onSuccess func(), onGoAway func(GoAwayReason), onClose func()) (_ *http2Client, err error) { scheme := "http" ctx, cancel := context.WithCancel(ctx) defer func() { @@ -170,39 +167,55 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr TargetInfo, opts Conne conn.Close() } }(conn) + kp := opts.KeepaliveParams + // Validate keepalive parameters. + if kp.Time == 0 { + kp.Time = defaultClientKeepaliveTime + } + if kp.Timeout == 0 { + kp.Timeout = defaultClientKeepaliveTimeout + } + keepaliveEnabled := false + if kp.Time != infinity { + if err = syscall.SetTCPUserTimeout(conn, kp.Timeout); err != nil { + return nil, connectionErrorf(false, err, "transport: failed to set TCP_USER_TIMEOUT: %v", err) + } + keepaliveEnabled = true + } var ( isSecure bool authInfo credentials.AuthInfo ) - if creds := opts.TransportCredentials; creds != nil { + transportCreds := opts.TransportCredentials + perRPCCreds := opts.PerRPCCredentials + + if b := opts.CredsBundle; b != nil { + if t := b.TransportCredentials(); t != nil { + transportCreds = t + } + if t := b.PerRPCCredentials(); t != nil { + perRPCCreds = append(perRPCCreds, t) + } + } + if transportCreds != nil { scheme = "https" - conn, authInfo, err = creds.ClientHandshake(connectCtx, addr.Authority, conn) + conn, authInfo, err = transportCreds.ClientHandshake(connectCtx, addr.Authority, conn) if err != nil { return nil, connectionErrorf(isTemporary(err), err, "transport: authentication handshake failed: %v", err) } isSecure = true } - kp := opts.KeepaliveParams - // Validate keepalive parameters. - if kp.Time == 0 { - kp.Time = defaultClientKeepaliveTime - } - if kp.Timeout == 0 { - kp.Timeout = defaultClientKeepaliveTimeout - } dynamicWindow := true icwz := int32(initialWindowSize) if opts.InitialConnWindowSize >= defaultWindowSize { icwz = opts.InitialConnWindowSize dynamicWindow = false } - writeBufSize := defaultWriteBufSize - if opts.WriteBufferSize > 0 { - writeBufSize = opts.WriteBufferSize - } - readBufSize := defaultReadBufSize - if opts.ReadBufferSize > 0 { - readBufSize = opts.ReadBufferSize + writeBufSize := opts.WriteBufferSize + readBufSize := opts.ReadBufferSize + maxHeaderListSize := defaultClientMaxHeaderListSize + if opts.MaxHeaderListSize != nil { + maxHeaderListSize = *opts.MaxHeaderListSize } t := &http2Client{ ctx: ctx, @@ -218,12 +231,12 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr TargetInfo, opts Conne writerDone: make(chan struct{}), goAway: make(chan struct{}), awakenKeepalive: make(chan struct{}, 1), - framer: newFramer(conn, writeBufSize, readBufSize), + framer: newFramer(conn, writeBufSize, readBufSize, maxHeaderListSize), fc: &trInFlow{limit: uint32(icwz)}, scheme: scheme, activeStreams: make(map[uint32]*Stream), isSecure: isSecure, - creds: opts.PerRPCCredentials, + perRPCCreds: perRPCCreds, kp: kp, statsHandler: opts.StatsHandler, initialWindowSize: initialWindowSize, @@ -232,6 +245,10 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr TargetInfo, opts Conne maxConcurrentStreams: defaultMaxStreamsClient, streamQuota: defaultMaxStreamsClient, streamsQuotaAvailable: make(chan struct{}, 1), + czData: new(channelzData), + onGoAway: onGoAway, + onClose: onClose, + keepaliveEnabled: keepaliveEnabled, } t.controlBuf = newControlBuffer(t.ctxDone) if opts.InitialWindowSize >= defaultWindowSize { @@ -258,16 +275,16 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr TargetInfo, opts Conne t.statsHandler.HandleConn(t.ctx, connBegin) } if channelz.IsOn() { - t.channelzID = channelz.RegisterNormalSocket(t, opts.ChannelzParentID, "") + t.channelzID = channelz.RegisterNormalSocket(t, opts.ChannelzParentID, fmt.Sprintf("%s -> %s", t.localAddr, t.remoteAddr)) } - if t.kp.Time != infinity { - t.keepaliveEnabled = true + if t.keepaliveEnabled { go t.keepalive() } // Start the reader goroutine for incoming message. Each transport has // a dedicated goroutine which reads HTTP2 frame from network. Then it // dispatches the frame to the corresponding stream entity. go t.reader() + // Send connection preface to server. n, err := t.conn.Write(clientPreface) if err != nil { @@ -278,14 +295,21 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr TargetInfo, opts Conne t.Close() return nil, connectionErrorf(true, err, "transport: preface mismatch, wrote %d bytes; want %d", n, len(clientPreface)) } + var ss []http2.Setting + if t.initialWindowSize != defaultWindowSize { - err = t.framer.fr.WriteSettings(http2.Setting{ + ss = append(ss, http2.Setting{ ID: http2.SettingInitialWindowSize, Val: uint32(t.initialWindowSize), }) - } else { - err = t.framer.fr.WriteSettings() } + if opts.MaxHeaderListSize != nil { + ss = append(ss, http2.Setting{ + ID: http2.SettingMaxHeaderListSize, + Val: *opts.MaxHeaderListSize, + }) + } + err = t.framer.fr.WriteSettings(ss...) if err != nil { t.Close() return nil, connectionErrorf(true, err, "transport: failed to write initial settings frame: %v", err) @@ -297,6 +321,7 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr TargetInfo, opts Conne return nil, connectionErrorf(true, err, "transport: failed to write window update: %v", err) } } + t.framer.writer.Flush() go func() { t.loopy = newLoopyWriter(clientSide, t.framer, t.controlBuf, t.bdpEst) @@ -379,6 +404,9 @@ func (t *http2Client) createHeaderFields(ctx context.Context, callHdr *CallHdr) headerFields = append(headerFields, hpack.HeaderField{Name: "content-type", Value: contentType(callHdr.ContentSubtype)}) headerFields = append(headerFields, hpack.HeaderField{Name: "user-agent", Value: t.userAgent}) headerFields = append(headerFields, hpack.HeaderField{Name: "te", Value: "trailers"}) + if callHdr.PreviousAttempts > 0 { + headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-previous-rpc-attempts", Value: strconv.Itoa(callHdr.PreviousAttempts)}) + } if callHdr.SendCompress != "" { headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-encoding", Value: callHdr.SendCompress}) @@ -442,7 +470,7 @@ func (t *http2Client) createHeaderFields(ctx context.Context, callHdr *CallHdr) func (t *http2Client) createAudience(callHdr *CallHdr) string { // Create an audience string only if needed. - if len(t.creds) == 0 && callHdr.Creds == nil { + if len(t.perRPCCreds) == 0 && callHdr.Creds == nil { return "" } // Construct URI required to get auth request metadata. @@ -457,14 +485,14 @@ func (t *http2Client) createAudience(callHdr *CallHdr) string { func (t *http2Client) getTrAuthData(ctx context.Context, audience string) (map[string]string, error) { authData := map[string]string{} - for _, c := range t.creds { + for _, c := range t.perRPCCreds { data, err := c.GetRequestMetadata(ctx, audience) if err != nil { if _, ok := status.FromError(err); ok { return nil, err } - return nil, streamErrorf(codes.Unauthenticated, "transport: %v", err) + return nil, status.Errorf(codes.Unauthenticated, "transport: %v", err) } for k, v := range data { // Capital header names are illegal in HTTP/2. @@ -482,11 +510,11 @@ func (t *http2Client) getCallAuthData(ctx context.Context, audience string, call // options, then both sets of credentials will be applied. if callCreds := callHdr.Creds; callCreds != nil { if !t.isSecure && callCreds.RequireTransportSecurity() { - return nil, streamErrorf(codes.Unauthenticated, "transport: cannot send secure credentials on an insecure connection") + return nil, status.Error(codes.Unauthenticated, "transport: cannot send secure credentials on an insecure connection") } data, err := callCreds.GetRequestMetadata(ctx, audience) if err != nil { - return nil, streamErrorf(codes.Internal, "transport: %v", err) + return nil, status.Errorf(codes.Internal, "transport: %v", err) } for k, v := range data { // Capital header names are illegal in HTTP/2 @@ -538,10 +566,8 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Strea } t.activeStreams[id] = s if channelz.IsOn() { - t.czmu.Lock() - t.streamsStarted++ - t.lastStreamCreated = time.Now() - t.czmu.Unlock() + atomic.AddInt64(&t.czData.streamsStarted, 1) + atomic.StoreInt64(&t.czData.lastStreamCreatedTime, time.Now().UnixNano()) } var sendPing bool // If the number of active streams change from 0 to 1, then check if keepalive @@ -590,14 +616,40 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Strea } return true } + var hdrListSizeErr error + checkForHeaderListSize := func(it interface{}) bool { + if t.maxSendHeaderListSize == nil { + return true + } + hdrFrame := it.(*headerFrame) + var sz int64 + for _, f := range hdrFrame.hf { + if sz += int64(f.Size()); sz > int64(*t.maxSendHeaderListSize) { + hdrListSizeErr = status.Errorf(codes.Internal, "header list size to send violates the maximum size (%d bytes) set by server", *t.maxSendHeaderListSize) + return false + } + } + return true + } for { - success, err := t.controlBuf.executeAndPut(checkForStreamQuota, hdr) + success, err := t.controlBuf.executeAndPut(func(it interface{}) bool { + if !checkForStreamQuota(it) { + return false + } + if !checkForHeaderListSize(it) { + return false + } + return true + }, hdr) if err != nil { return nil, err } if success { break } + if hdrListSizeErr != nil { + return nil, hdrListSizeErr + } firstTry = false select { case <-ch: @@ -633,13 +685,15 @@ func (t *http2Client) CloseStream(s *Stream, err error) { rst = true rstCode = http2.ErrCodeCancel } - t.closeStream(s, err, rst, rstCode, nil, nil, false) + t.closeStream(s, err, rst, rstCode, status.Convert(err), nil, false) } func (t *http2Client) closeStream(s *Stream, err error, rst bool, rstCode http2.ErrCode, st *status.Status, mdata map[string][]string, eosReceived bool) { // Set stream status to done. if s.swapState(streamDone) == streamDone { - // If it was already done, return. + // If it was already done, return. If multiple closeStream calls + // happen simultaneously, wait for the first to finish. + <-s.done return } // status and trailers can be updated here without any synchronization because the stream goroutine will @@ -653,10 +707,9 @@ func (t *http2Client) closeStream(s *Stream, err error, rst bool, rstCode http2. // This will unblock reads eventually. s.write(recvMsg{err: err}) } - // This will unblock write. - close(s.done) // If headerChan isn't closed, then close it. if atomic.SwapUint32(&s.headerDone, 1) == 0 { + s.noHeaders = true close(s.headerChan) } cleanup := &cleanupStream{ @@ -668,13 +721,11 @@ func (t *http2Client) closeStream(s *Stream, err error, rst bool, rstCode http2. } t.mu.Unlock() if channelz.IsOn() { - t.czmu.Lock() if eosReceived { - t.streamsSucceeded++ + atomic.AddInt64(&t.czData.streamsSucceeded, 1) } else { - t.streamsFailed++ + atomic.AddInt64(&t.czData.streamsFailed, 1) } - t.czmu.Unlock() } }, rst: rst, @@ -691,11 +742,17 @@ func (t *http2Client) closeStream(s *Stream, err error, rst bool, rstCode http2. return true } t.controlBuf.executeAndPut(addBackStreamQuota, cleanup) + // This will unblock write. + close(s.done) } // Close kicks off the shutdown process of the transport. This should be called // only once on a transport. Once it is called, the transport should not be // accessed any more. +// +// This method blocks until the addrConn that initiated this transport is +// re-connected. This happens because t.onClose() begins reconnect logic at the +// addrConn level and blocks until the addrConn is successfully connected. func (t *http2Client) Close() error { t.mu.Lock() // Make sure we only Close once. @@ -715,7 +772,7 @@ func (t *http2Client) Close() error { } // Notify all active streams. for _, s := range streams { - t.closeStream(s, ErrConnClosing, false, http2.ErrCodeNo, nil, nil, false) + t.closeStream(s, ErrConnClosing, false, http2.ErrCodeNo, status.New(codes.Unavailable, ErrConnClosing.Desc), nil, false) } if t.statsHandler != nil { connEnd := &stats.ConnEnd{ @@ -723,6 +780,7 @@ func (t *http2Client) Close() error { } t.statsHandler.HandleConn(t.ctx, connEnd) } + go t.onClose() return err } @@ -909,6 +967,13 @@ func (t *http2Client) handleRSTStream(f *http2.RSTStreamFrame) { warningf("transport: http2Client.handleRSTStream found no mapped gRPC status for the received http2 error %v", f.ErrCode) statusCode = codes.Unknown } + if statusCode == codes.Canceled { + // Our deadline was already exceeded, and that was likely the cause of + // this cancelation. Alter the status code accordingly. + if d, ok := s.ctx.Deadline(); ok && d.After(time.Now()) { + statusCode = codes.DeadlineExceeded + } + } t.closeStream(s, io.EOF, false, http2.ErrCodeNo, status.Newf(statusCode, "stream terminated by RST_STREAM with error code: %v", f.ErrCode), nil, false) } @@ -918,13 +983,20 @@ func (t *http2Client) handleSettings(f *http2.SettingsFrame, isFirst bool) { } var maxStreams *uint32 var ss []http2.Setting + var updateFuncs []func() f.ForeachSetting(func(s http2.Setting) error { - if s.ID == http2.SettingMaxConcurrentStreams { + switch s.ID { + case http2.SettingMaxConcurrentStreams: maxStreams = new(uint32) *maxStreams = s.Val - return nil + case http2.SettingMaxHeaderListSize: + updateFuncs = append(updateFuncs, func() { + t.maxSendHeaderListSize = new(uint32) + *t.maxSendHeaderListSize = s.Val + }) + default: + ss = append(ss, s) } - ss = append(ss, s) return nil }) if isFirst && maxStreams == nil { @@ -934,21 +1006,24 @@ func (t *http2Client) handleSettings(f *http2.SettingsFrame, isFirst bool) { sf := &incomingSettings{ ss: ss, } - if maxStreams == nil { - t.controlBuf.put(sf) - return + if maxStreams != nil { + updateStreamQuota := func() { + delta := int64(*maxStreams) - int64(t.maxConcurrentStreams) + t.maxConcurrentStreams = *maxStreams + t.streamQuota += delta + if delta > 0 && t.waitingStreams > 0 { + close(t.streamsQuotaAvailable) // wake all of them up. + t.streamsQuotaAvailable = make(chan struct{}, 1) + } + } + updateFuncs = append(updateFuncs, updateStreamQuota) } - updateStreamQuota := func(interface{}) bool { - delta := int64(*maxStreams) - int64(t.maxConcurrentStreams) - t.maxConcurrentStreams = *maxStreams - t.streamQuota += delta - if delta > 0 && t.waitingStreams > 0 { - close(t.streamsQuotaAvailable) // wake all of them up. - t.streamsQuotaAvailable = make(chan struct{}, 1) + t.controlBuf.executeAndPut(func(interface{}) bool { + for _, f := range updateFuncs { + f() } return true - } - t.controlBuf.executeAndPut(updateStreamQuota, sf) + }, sf) } func (t *http2Client) handlePing(f *http2.PingFrame) { @@ -1002,6 +1077,9 @@ func (t *http2Client) handleGoAway(f *http2.GoAwayFrame) { close(t.goAway) t.state = draining t.controlBuf.put(&incomingGoAway{}) + + // This has to be a new goroutine because we're still using the current goroutine to read in the transport. + t.onGoAway(t.goAwayReason) } // All streams with IDs greater than the GoAwayId // and smaller than the previous GoAway ID should be killed. @@ -1059,8 +1137,8 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) { } atomic.StoreUint32(&s.bytesReceived, 1) var state decodeState - if err := state.decodeResponseHeader(frame); err != nil { - t.closeStream(s, err, true, http2.ErrCodeProtocol, nil, nil, false) + if err := state.decodeHeader(frame); err != nil { + t.closeStream(s, err, true, http2.ErrCodeProtocol, status.New(codes.Internal, err.Error()), nil, false) // Something wrong. Stops reading even when there is remaining. return } @@ -1096,13 +1174,17 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) { if len(state.mdata) > 0 { s.header = state.mdata } + } else { + s.noHeaders = true } close(s.headerChan) } if !endStream { return } - t.closeStream(s, io.EOF, false, http2.ErrCodeNo, state.status(), state.mdata, true) + // if client received END_STREAM from server while stream was still active, send RST_STREAM + rst := s.getState() == streamActive + t.closeStream(s, io.EOF, rst, http2.ErrCodeNo, state.status(), state.mdata, true) } // reader runs as a separate goroutine in charge of reading data from network @@ -1116,15 +1198,16 @@ func (t *http2Client) reader() { // Check the validity of server preface. frame, err := t.framer.fr.ReadFrame() if err != nil { - t.Close() + t.Close() // this kicks off resetTransport, so must be last before return return } + t.conn.SetReadDeadline(time.Time{}) // reset deadline once we get the settings frame (we didn't time out, yay!) if t.keepaliveEnabled { atomic.CompareAndSwapUint32(&t.activity, 0, 1) } sf, ok := frame.(*http2.SettingsFrame) if !ok { - t.Close() + t.Close() // this kicks off resetTransport, so must be last before return return } t.onSuccess() @@ -1146,7 +1229,9 @@ func (t *http2Client) reader() { t.mu.Unlock() if s != nil { // use error detail to provide better err message - t.closeStream(s, streamErrorf(http2ErrConvTab[se.Code], "%v", t.framer.fr.ErrorDetail()), true, http2.ErrCodeProtocol, nil, nil, false) + code := http2ErrConvTab[se.Code] + msg := t.framer.fr.ErrorDetail().Error() + t.closeStream(s, status.Error(code, msg), true, http2.ErrCodeProtocol, status.New(code, msg), nil, false) } continue } else { @@ -1203,9 +1288,7 @@ func (t *http2Client) keepalive() { } else { t.mu.Unlock() if channelz.IsOn() { - t.czmu.Lock() - t.kpCount++ - t.czmu.Unlock() + atomic.AddInt64(&t.czData.kpCount, 1) } // Send ping. t.controlBuf.put(p) @@ -1245,41 +1328,37 @@ func (t *http2Client) GoAway() <-chan struct{} { } func (t *http2Client) ChannelzMetric() *channelz.SocketInternalMetric { - t.czmu.RLock() s := channelz.SocketInternalMetric{ - StreamsStarted: t.streamsStarted, - StreamsSucceeded: t.streamsSucceeded, - StreamsFailed: t.streamsFailed, - MessagesSent: t.msgSent, - MessagesReceived: t.msgRecv, - KeepAlivesSent: t.kpCount, - LastLocalStreamCreatedTimestamp: t.lastStreamCreated, - LastMessageSentTimestamp: t.lastMsgSent, - LastMessageReceivedTimestamp: t.lastMsgRecv, + StreamsStarted: atomic.LoadInt64(&t.czData.streamsStarted), + StreamsSucceeded: atomic.LoadInt64(&t.czData.streamsSucceeded), + StreamsFailed: atomic.LoadInt64(&t.czData.streamsFailed), + MessagesSent: atomic.LoadInt64(&t.czData.msgSent), + MessagesReceived: atomic.LoadInt64(&t.czData.msgRecv), + KeepAlivesSent: atomic.LoadInt64(&t.czData.kpCount), + LastLocalStreamCreatedTimestamp: time.Unix(0, atomic.LoadInt64(&t.czData.lastStreamCreatedTime)), + LastMessageSentTimestamp: time.Unix(0, atomic.LoadInt64(&t.czData.lastMsgSentTime)), + LastMessageReceivedTimestamp: time.Unix(0, atomic.LoadInt64(&t.czData.lastMsgRecvTime)), LocalFlowControlWindow: int64(t.fc.getSize()), - //socket options - LocalAddr: t.localAddr, - RemoteAddr: t.remoteAddr, - // Security + SocketOptions: channelz.GetSocketOption(t.conn), + LocalAddr: t.localAddr, + RemoteAddr: t.remoteAddr, // RemoteName : } - t.czmu.RUnlock() + if au, ok := t.authInfo.(credentials.ChannelzSecurityInfo); ok { + s.Security = au.GetSecurityValue() + } s.RemoteFlowControlWindow = t.getOutFlowWindow() return &s } func (t *http2Client) IncrMsgSent() { - t.czmu.Lock() - t.msgSent++ - t.lastMsgSent = time.Now() - t.czmu.Unlock() + atomic.AddInt64(&t.czData.msgSent, 1) + atomic.StoreInt64(&t.czData.lastMsgSentTime, time.Now().UnixNano()) } func (t *http2Client) IncrMsgRecv() { - t.czmu.Lock() - t.msgRecv++ - t.lastMsgRecv = time.Now() - t.czmu.Unlock() + atomic.AddInt64(&t.czData.msgRecv, 1) + atomic.StoreInt64(&t.czData.lastMsgRecvTime, time.Now().UnixNano()) } func (t *http2Client) getOutFlowWindow() int64 { diff --git a/vendor/google.golang.org/grpc/transport/http2_server.go b/vendor/google.golang.org/grpc/internal/transport/http2_server.go similarity index 86% rename from vendor/google.golang.org/grpc/transport/http2_server.go rename to vendor/google.golang.org/grpc/internal/transport/http2_server.go index 19acedb2b0208f66564eb08be3551f39ba2dc5a5..df2740398bd404712913aac4c32984835c6cd595 100644 --- a/vendor/google.golang.org/grpc/transport/http2_server.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_server.go @@ -20,6 +20,7 @@ package transport import ( "bytes" + "context" "errors" "fmt" "io" @@ -31,7 +32,6 @@ import ( "time" "github.com/golang/protobuf/proto" - "golang.org/x/net/context" "golang.org/x/net/http2" "golang.org/x/net/http2/hpack" @@ -48,9 +48,14 @@ import ( "google.golang.org/grpc/tap" ) -// ErrIllegalHeaderWrite indicates that setting header is illegal because of -// the stream's state. -var ErrIllegalHeaderWrite = errors.New("transport: the stream is done or WriteHeader was already called") +var ( + // ErrIllegalHeaderWrite indicates that setting header is illegal because of + // the stream's state. + ErrIllegalHeaderWrite = errors.New("transport: the stream is done or WriteHeader was already called") + // ErrHeaderListSizeLimitViolation indicates that the header list size is larger + // than the limit set by peer. + ErrHeaderListSizeLimitViolation = errors.New("transport: trying to send header list size larger than the limit set by peer") +) // http2Server implements the ServerTransport interface with HTTP2. type http2Server struct { @@ -89,9 +94,10 @@ type http2Server struct { // Flag to signify that number of ping strikes should be reset to 0. // This is set whenever data or header frames are sent. // 1 means yes. - resetPingStrikes uint32 // Accessed atomically. - initialWindowSize int32 - bdpEst *bdpEstimator + resetPingStrikes uint32 // Accessed atomically. + initialWindowSize int32 + bdpEst *bdpEstimator + maxSendHeaderListSize *uint32 mu sync.Mutex // guard the following @@ -112,33 +118,19 @@ type http2Server struct { // Fields below are for channelz metric collection. channelzID int64 // channelz unique identification number - czmu sync.RWMutex - kpCount int64 - // The number of streams that have started, including already finished ones. - streamsStarted int64 - // The number of streams that have ended successfully by sending frame with - // EoS bit set. - streamsSucceeded int64 - streamsFailed int64 - lastStreamCreated time.Time - msgSent int64 - msgRecv int64 - lastMsgSent time.Time - lastMsgRecv time.Time + czData *channelzData } // newHTTP2Server constructs a ServerTransport based on HTTP2. ConnectionError is // returned if something goes wrong. func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err error) { - writeBufSize := defaultWriteBufSize - if config.WriteBufferSize > 0 { - writeBufSize = config.WriteBufferSize - } - readBufSize := defaultReadBufSize - if config.ReadBufferSize > 0 { - readBufSize = config.ReadBufferSize + writeBufSize := config.WriteBufferSize + readBufSize := config.ReadBufferSize + maxHeaderListSize := defaultServerMaxHeaderListSize + if config.MaxHeaderListSize != nil { + maxHeaderListSize = *config.MaxHeaderListSize } - framer := newFramer(conn, writeBufSize, readBufSize) + framer := newFramer(conn, writeBufSize, readBufSize, maxHeaderListSize) // Send initial settings as connection preface to client. var isettings []http2.Setting // TODO(zhaoq): Have a better way to signal "no limit" because 0 is @@ -168,6 +160,12 @@ func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err ID: http2.SettingInitialWindowSize, Val: uint32(iwz)}) } + if config.MaxHeaderListSize != nil { + isettings = append(isettings, http2.Setting{ + ID: http2.SettingMaxHeaderListSize, + Val: *config.MaxHeaderListSize, + }) + } if err := framer.fr.WriteSettings(isettings...); err != nil { return nil, connectionErrorf(false, err, "transport: %v", err) } @@ -221,6 +219,7 @@ func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err idle: time.Now(), kep: kep, initialWindowSize: iwz, + czData: new(channelzData), } t.controlBuf = newControlBuffer(t.ctxDone) if dynamicWindow { @@ -238,7 +237,7 @@ func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err t.stats.HandleConn(t.ctx, connBegin) } if channelz.IsOn() { - t.channelzID = channelz.RegisterNormalSocket(t, config.ChannelzParentID, "") + t.channelzID = channelz.RegisterNormalSocket(t, config.ChannelzParentID, fmt.Sprintf("%s -> %s", t.remoteAddr, t.localAddr)) } t.framer.writer.Flush() @@ -285,21 +284,19 @@ func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err } // operateHeader takes action on the decoded headers. -func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(*Stream), traceCtx func(context.Context, string) context.Context) (close bool) { +func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(*Stream), traceCtx func(context.Context, string) context.Context) (fatal bool) { streamID := frame.Header().StreamID - var state decodeState - for _, hf := range frame.Fields { - if err := state.processHeaderField(hf); err != nil { - if se, ok := err.(StreamError); ok { - t.controlBuf.put(&cleanupStream{ - streamID: streamID, - rst: true, - rstCode: statusCodeConvTab[se.Code], - onWrite: func() {}, - }) - } - return + state := decodeState{serverSide: true} + if err := state.decodeHeader(frame); err != nil { + if se, ok := status.FromError(err); ok { + t.controlBuf.put(&cleanupStream{ + streamID: streamID, + rst: true, + rstCode: statusCodeConvTab[se.Code()], + onWrite: func() {}, + }) } + return false } buf := newRecvBuffer() @@ -353,13 +350,13 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func( rstCode: http2.ErrCodeRefusedStream, onWrite: func() {}, }) - return + return false } } t.mu.Lock() if t.state != reachable { t.mu.Unlock() - return + return false } if uint32(len(t.activeStreams)) >= t.maxStreams { t.mu.Unlock() @@ -369,7 +366,7 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func( rstCode: http2.ErrCodeRefusedStream, onWrite: func() {}, }) - return + return false } if streamID%2 != 1 || streamID <= t.maxStreamID { t.mu.Unlock() @@ -384,10 +381,8 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func( } t.mu.Unlock() if channelz.IsOn() { - t.czmu.Lock() - t.streamsStarted++ - t.lastStreamCreated = time.Now() - t.czmu.Unlock() + atomic.AddInt64(&t.czData.streamsStarted, 1) + atomic.StoreInt64(&t.czData.lastStreamCreatedTime, time.Now().UnixNano()) } s.requestRead = func(n int) { t.adjustWindow(s, uint32(n)) @@ -422,7 +417,7 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func( wq: s.wq, }) handle(s) - return + return false } // HandleStreams receives incoming streams using the given handler. This is @@ -619,11 +614,25 @@ func (t *http2Server) handleSettings(f *http2.SettingsFrame) { return } var ss []http2.Setting + var updateFuncs []func() f.ForeachSetting(func(s http2.Setting) error { - ss = append(ss, s) + switch s.ID { + case http2.SettingMaxHeaderListSize: + updateFuncs = append(updateFuncs, func() { + t.maxSendHeaderListSize = new(uint32) + *t.maxSendHeaderListSize = s.Val + }) + default: + ss = append(ss, s) + } return nil }) - t.controlBuf.put(&incomingSettings{ + t.controlBuf.executeAndPut(func(interface{}) bool { + for _, f := range updateFuncs { + f() + } + return true + }, &incomingSettings{ ss: ss, }) } @@ -703,6 +712,21 @@ func appendHeaderFieldsFromMD(headerFields []hpack.HeaderField, md metadata.MD) return headerFields } +func (t *http2Server) checkForHeaderListSize(it interface{}) bool { + if t.maxSendHeaderListSize == nil { + return true + } + hdrFrame := it.(*headerFrame) + var sz int64 + for _, f := range hdrFrame.hf { + if sz += int64(f.Size()); sz > int64(*t.maxSendHeaderListSize) { + errorf("header list size to send violates the maximum size (%d bytes) set by client", *t.maxSendHeaderListSize) + return false + } + } + return true +} + // WriteHeader sends the header metedata md back to the client. func (t *http2Server) WriteHeader(s *Stream, md metadata.MD) error { if s.updateHeaderSent() || s.getState() == streamDone { @@ -716,12 +740,15 @@ func (t *http2Server) WriteHeader(s *Stream, md metadata.MD) error { s.header = md } } - t.writeHeaderLocked(s) + if err := t.writeHeaderLocked(s); err != nil { + s.hdrMu.Unlock() + return err + } s.hdrMu.Unlock() return nil } -func (t *http2Server) writeHeaderLocked(s *Stream) { +func (t *http2Server) writeHeaderLocked(s *Stream) error { // TODO(mmukhi): Benchmark if the performance gets better if count the metadata and other header fields // first and create a slice of that exact size. headerFields := make([]hpack.HeaderField, 0, 2) // at least :status, content-type will be there if none else. @@ -731,7 +758,7 @@ func (t *http2Server) writeHeaderLocked(s *Stream) { headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-encoding", Value: s.sendCompress}) } headerFields = appendHeaderFieldsFromMD(headerFields, s.header) - t.controlBuf.put(&headerFrame{ + success, err := t.controlBuf.executeAndPut(t.checkForHeaderListSize, &headerFrame{ streamID: s.id, hf: headerFields, endStream: false, @@ -739,12 +766,20 @@ func (t *http2Server) writeHeaderLocked(s *Stream) { atomic.StoreUint32(&t.resetPingStrikes, 1) }, }) + if !success { + if err != nil { + return err + } + t.closeStream(s, true, http2.ErrCodeInternal, nil, false) + return ErrHeaderListSizeLimitViolation + } if t.stats != nil { // Note: WireLength is not set in outHeader. // TODO(mmukhi): Revisit this later, if needed. outHeader := &stats.OutHeader{} t.stats.HandleRPC(s.Context(), outHeader) } + return nil } // WriteStatus sends stream status to the client and terminates the stream. @@ -761,7 +796,10 @@ func (t *http2Server) WriteStatus(s *Stream, st *status.Status) error { headerFields := make([]hpack.HeaderField, 0, 2) // grpc-status and grpc-message will be there if none else. if !s.updateHeaderSent() { // No headers have been sent. if len(s.header) > 0 { // Send a separate header frame. - t.writeHeaderLocked(s) + if err := t.writeHeaderLocked(s); err != nil { + s.hdrMu.Unlock() + return err + } } else { // Send a trailer only response. headerFields = append(headerFields, hpack.HeaderField{Name: ":status", Value: "200"}) headerFields = append(headerFields, hpack.HeaderField{Name: "content-type", Value: contentType(s.contentSubtype)}) @@ -791,6 +829,14 @@ func (t *http2Server) WriteStatus(s *Stream, st *status.Status) error { }, } s.hdrMu.Unlock() + success, err := t.controlBuf.execute(t.checkForHeaderListSize, trailingHeader) + if !success { + if err != nil { + return err + } + t.closeStream(s, true, http2.ErrCodeInternal, nil, false) + return ErrHeaderListSizeLimitViolation + } t.closeStream(s, false, 0, trailingHeader, true) if t.stats != nil { t.stats.HandleRPC(s.Context(), &stats.OutTrailer{}) @@ -804,7 +850,7 @@ func (t *http2Server) Write(s *Stream, hdr []byte, data []byte, opts *Options) e if !s.isHeaderSent() { // Headers haven't been written yet. if err := t.WriteHeader(s, nil); err != nil { // TODO(mmukhi, dfawley): Make sure this is the right code to return. - return streamErrorf(codes.Internal, "transport: %v", err) + return status.Errorf(codes.Internal, "transport: %v", err) } } else { // Writing headers checks for this condition. @@ -918,9 +964,7 @@ func (t *http2Server) keepalive() { } pingSent = true if channelz.IsOn() { - t.czmu.Lock() - t.kpCount++ - t.czmu.Unlock() + atomic.AddInt64(&t.czData.kpCount, 1) } t.controlBuf.put(p) keepalive.Reset(t.kp.Timeout) @@ -985,13 +1029,11 @@ func (t *http2Server) closeStream(s *Stream, rst bool, rstCode http2.ErrCode, hd } t.mu.Unlock() if channelz.IsOn() { - t.czmu.Lock() if eosReceived { - t.streamsSucceeded++ + atomic.AddInt64(&t.czData.streamsSucceeded, 1) } else { - t.streamsFailed++ + atomic.AddInt64(&t.czData.streamsFailed, 1) } - t.czmu.Unlock() } }, } @@ -1079,41 +1121,37 @@ func (t *http2Server) outgoingGoAwayHandler(g *goAway) (bool, error) { } func (t *http2Server) ChannelzMetric() *channelz.SocketInternalMetric { - t.czmu.RLock() s := channelz.SocketInternalMetric{ - StreamsStarted: t.streamsStarted, - StreamsSucceeded: t.streamsSucceeded, - StreamsFailed: t.streamsFailed, - MessagesSent: t.msgSent, - MessagesReceived: t.msgRecv, - KeepAlivesSent: t.kpCount, - LastRemoteStreamCreatedTimestamp: t.lastStreamCreated, - LastMessageSentTimestamp: t.lastMsgSent, - LastMessageReceivedTimestamp: t.lastMsgRecv, + StreamsStarted: atomic.LoadInt64(&t.czData.streamsStarted), + StreamsSucceeded: atomic.LoadInt64(&t.czData.streamsSucceeded), + StreamsFailed: atomic.LoadInt64(&t.czData.streamsFailed), + MessagesSent: atomic.LoadInt64(&t.czData.msgSent), + MessagesReceived: atomic.LoadInt64(&t.czData.msgRecv), + KeepAlivesSent: atomic.LoadInt64(&t.czData.kpCount), + LastRemoteStreamCreatedTimestamp: time.Unix(0, atomic.LoadInt64(&t.czData.lastStreamCreatedTime)), + LastMessageSentTimestamp: time.Unix(0, atomic.LoadInt64(&t.czData.lastMsgSentTime)), + LastMessageReceivedTimestamp: time.Unix(0, atomic.LoadInt64(&t.czData.lastMsgRecvTime)), LocalFlowControlWindow: int64(t.fc.getSize()), - //socket options - LocalAddr: t.localAddr, - RemoteAddr: t.remoteAddr, - // Security + SocketOptions: channelz.GetSocketOption(t.conn), + LocalAddr: t.localAddr, + RemoteAddr: t.remoteAddr, // RemoteName : } - t.czmu.RUnlock() + if au, ok := t.authInfo.(credentials.ChannelzSecurityInfo); ok { + s.Security = au.GetSecurityValue() + } s.RemoteFlowControlWindow = t.getOutFlowWindow() return &s } func (t *http2Server) IncrMsgSent() { - t.czmu.Lock() - t.msgSent++ - t.lastMsgSent = time.Now() - t.czmu.Unlock() + atomic.AddInt64(&t.czData.msgSent, 1) + atomic.StoreInt64(&t.czData.lastMsgSentTime, time.Now().UnixNano()) } func (t *http2Server) IncrMsgRecv() { - t.czmu.Lock() - t.msgRecv++ - t.lastMsgRecv = time.Now() - t.czmu.Unlock() + atomic.AddInt64(&t.czData.msgRecv, 1) + atomic.StoreInt64(&t.czData.lastMsgRecvTime, time.Now().UnixNano()) } func (t *http2Server) getOutFlowWindow() int64 { diff --git a/vendor/google.golang.org/grpc/transport/http_util.go b/vendor/google.golang.org/grpc/internal/transport/http_util.go similarity index 87% rename from vendor/google.golang.org/grpc/transport/http_util.go rename to vendor/google.golang.org/grpc/internal/transport/http_util.go index 7d15c7d74261c0cbbd8ce244ff4ea36b3668cdcf..77a2cfaaef336ab2de35e506884a0949341b3332 100644 --- a/vendor/google.golang.org/grpc/transport/http_util.go +++ b/vendor/google.golang.org/grpc/internal/transport/http_util.go @@ -23,6 +23,8 @@ import ( "bytes" "encoding/base64" "fmt" + "io" + "math" "net" "net/http" "strconv" @@ -43,9 +45,6 @@ const ( http2MaxFrameLen = 16384 // 16KB frame // http://http2.github.io/http2-spec/#SettingValues http2InitHeaderTableSize = 4096 - // http2IOBufSize specifies the buffer size for sending frames. - defaultWriteBufSize = 32 * 1024 - defaultReadBufSize = 32 * 1024 // baseContentType is the base content-type for gRPC. This is a valid // content-type on it's own, but can also include a content-subtype such as // "proto" as a suffix after "+" or ";". See @@ -121,6 +120,8 @@ type decodeState struct { statsTags []byte statsTrace []byte contentSubtype string + // whether decoding on server side or not + serverSide bool } // isReservedHeader checks whether hdr belongs to HTTP2 headers @@ -139,6 +140,9 @@ func isReservedHeader(hdr string) bool { "grpc-status", "grpc-timeout", "grpc-status-details-bin", + // Intentionally exclude grpc-previous-rpc-attempts and + // grpc-retry-pushback-ms, which are "reserved", but their API + // intentionally works via metadata. "te": return true default: @@ -146,8 +150,8 @@ func isReservedHeader(hdr string) bool { } } -// isWhitelistedHeader checks whether hdr should be propagated -// into metadata visible to users. +// isWhitelistedHeader checks whether hdr should be propagated into metadata +// visible to users, even though it is classified as "reserved", above. func isWhitelistedHeader(hdr string) bool { switch hdr { case ":authority", "user-agent": @@ -234,13 +238,22 @@ func decodeMetadataHeader(k, v string) (string, error) { return v, nil } -func (d *decodeState) decodeResponseHeader(frame *http2.MetaHeadersFrame) error { +func (d *decodeState) decodeHeader(frame *http2.MetaHeadersFrame) error { + // frame.Truncated is set to true when framer detects that the current header + // list size hits MaxHeaderListSize limit. + if frame.Truncated { + return status.Error(codes.Internal, "peer header list size exceeded limit") + } for _, hf := range frame.Fields { if err := d.processHeaderField(hf); err != nil { return err } } + if d.serverSide { + return nil + } + // If grpc status exists, no need to check further. if d.rawStatusCode != nil || d.statusGen != nil { return nil @@ -249,7 +262,7 @@ func (d *decodeState) decodeResponseHeader(frame *http2.MetaHeadersFrame) error // If grpc status doesn't exist and http status doesn't exist, // then it's a malformed header. if d.httpStatus == nil { - return streamErrorf(codes.Internal, "malformed header: doesn't contain status(gRPC or HTTP)") + return status.Error(codes.Internal, "malformed header: doesn't contain status(gRPC or HTTP)") } if *(d.httpStatus) != http.StatusOK { @@ -257,7 +270,7 @@ func (d *decodeState) decodeResponseHeader(frame *http2.MetaHeadersFrame) error if !ok { code = codes.Unknown } - return streamErrorf(code, http.StatusText(*(d.httpStatus))) + return status.Error(code, http.StatusText(*(d.httpStatus))) } // gRPC status doesn't exist and http status is OK. @@ -269,7 +282,6 @@ func (d *decodeState) decodeResponseHeader(frame *http2.MetaHeadersFrame) error code := int(codes.Unknown) d.rawStatusCode = &code return nil - } func (d *decodeState) addMetadata(k, v string) { @@ -284,7 +296,7 @@ func (d *decodeState) processHeaderField(f hpack.HeaderField) error { case "content-type": contentSubtype, validContentType := contentSubtype(f.Value) if !validContentType { - return streamErrorf(codes.Internal, "transport: received the unexpected content-type %q", f.Value) + return status.Errorf(codes.Internal, "transport: received the unexpected content-type %q", f.Value) } d.contentSubtype = contentSubtype // TODO: do we want to propagate the whole content-type in the metadata, @@ -297,7 +309,7 @@ func (d *decodeState) processHeaderField(f hpack.HeaderField) error { case "grpc-status": code, err := strconv.Atoi(f.Value) if err != nil { - return streamErrorf(codes.Internal, "transport: malformed grpc-status: %v", err) + return status.Errorf(codes.Internal, "transport: malformed grpc-status: %v", err) } d.rawStatusCode = &code case "grpc-message": @@ -305,38 +317,38 @@ func (d *decodeState) processHeaderField(f hpack.HeaderField) error { case "grpc-status-details-bin": v, err := decodeBinHeader(f.Value) if err != nil { - return streamErrorf(codes.Internal, "transport: malformed grpc-status-details-bin: %v", err) + return status.Errorf(codes.Internal, "transport: malformed grpc-status-details-bin: %v", err) } s := &spb.Status{} if err := proto.Unmarshal(v, s); err != nil { - return streamErrorf(codes.Internal, "transport: malformed grpc-status-details-bin: %v", err) + return status.Errorf(codes.Internal, "transport: malformed grpc-status-details-bin: %v", err) } d.statusGen = status.FromProto(s) case "grpc-timeout": d.timeoutSet = true var err error if d.timeout, err = decodeTimeout(f.Value); err != nil { - return streamErrorf(codes.Internal, "transport: malformed time-out: %v", err) + return status.Errorf(codes.Internal, "transport: malformed time-out: %v", err) } case ":path": d.method = f.Value case ":status": code, err := strconv.Atoi(f.Value) if err != nil { - return streamErrorf(codes.Internal, "transport: malformed http-status: %v", err) + return status.Errorf(codes.Internal, "transport: malformed http-status: %v", err) } d.httpStatus = &code case "grpc-tags-bin": v, err := decodeBinHeader(f.Value) if err != nil { - return streamErrorf(codes.Internal, "transport: malformed grpc-tags-bin: %v", err) + return status.Errorf(codes.Internal, "transport: malformed grpc-tags-bin: %v", err) } d.statsTags = v d.addMetadata(f.Name, string(v)) case "grpc-trace-bin": v, err := decodeBinHeader(f.Value) if err != nil { - return streamErrorf(codes.Internal, "transport: malformed grpc-trace-bin: %v", err) + return status.Errorf(codes.Internal, "transport: malformed grpc-trace-bin: %v", err) } d.statsTrace = v d.addMetadata(f.Name, string(v)) @@ -424,6 +436,10 @@ func decodeTimeout(s string) (time.Duration, error) { if size < 2 { return 0, fmt.Errorf("transport: timeout string is too short: %q", s) } + if size > 9 { + // Spec allows for 8 digits plus the unit. + return 0, fmt.Errorf("transport: timeout string is too long: %q", s) + } unit := timeoutUnit(s[size-1]) d, ok := timeoutUnitToDuration(unit) if !ok { @@ -433,6 +449,11 @@ func decodeTimeout(s string) (time.Duration, error) { if err != nil { return 0, err } + const maxHours = math.MaxInt64 / int64(time.Hour) + if d == time.Hour && t > maxHours { + // This timeout would overflow math.MaxInt64; clamp it. + return time.Duration(math.MaxInt64), nil + } return d * time.Duration(t), nil } @@ -545,6 +566,9 @@ func (w *bufWriter) Write(b []byte) (n int, err error) { if w.err != nil { return 0, w.err } + if w.batchSize == 0 { // Buffer has been disabled. + return w.conn.Write(b) + } for len(b) > 0 { nn := copy(w.buf[w.offset:], b) b = b[nn:] @@ -577,8 +601,14 @@ type framer struct { fr *http2.Framer } -func newFramer(conn net.Conn, writeBufferSize, readBufferSize int) *framer { - r := bufio.NewReaderSize(conn, readBufferSize) +func newFramer(conn net.Conn, writeBufferSize, readBufferSize int, maxHeaderListSize uint32) *framer { + if writeBufferSize < 0 { + writeBufferSize = 0 + } + var r io.Reader = conn + if readBufferSize > 0 { + r = bufio.NewReaderSize(r, readBufferSize) + } w := newBufWriter(conn, writeBufferSize) f := &framer{ writer: w, @@ -587,6 +617,7 @@ func newFramer(conn net.Conn, writeBufferSize, readBufferSize int) *framer { // Opt-in to Frame reuse API on framer to reduce garbage. // Frames aren't safe to read from after a subsequent call to ReadFrame. f.fr.SetReuseFrames() + f.fr.MaxHeaderListSize = maxHeaderListSize f.fr.ReadMetaHeaders = hpack.NewDecoder(http2InitHeaderTableSize, nil) return f } diff --git a/vendor/google.golang.org/grpc/transport/http_util_test.go b/vendor/google.golang.org/grpc/internal/transport/http_util_test.go similarity index 100% rename from vendor/google.golang.org/grpc/transport/http_util_test.go rename to vendor/google.golang.org/grpc/internal/transport/http_util_test.go diff --git a/vendor/google.golang.org/grpc/transport/log.go b/vendor/google.golang.org/grpc/internal/transport/log.go similarity index 90% rename from vendor/google.golang.org/grpc/transport/log.go rename to vendor/google.golang.org/grpc/internal/transport/log.go index ac8e358c5c8c922237181e6492d373ca5003c1d8..879df80c4de7f9fa4ff4c0edf3fcfe8b5f317778 100644 --- a/vendor/google.golang.org/grpc/transport/log.go +++ b/vendor/google.golang.org/grpc/internal/transport/log.go @@ -42,9 +42,3 @@ func errorf(format string, args ...interface{}) { grpclog.Errorf(format, args...) } } - -func fatalf(format string, args ...interface{}) { - if grpclog.V(logLevel) { - grpclog.Fatalf(format, args...) - } -} diff --git a/vendor/google.golang.org/grpc/transport/transport.go b/vendor/google.golang.org/grpc/internal/transport/transport.go similarity index 84% rename from vendor/google.golang.org/grpc/transport/transport.go rename to vendor/google.golang.org/grpc/internal/transport/transport.go index f51f878884df5ab1588e375e0bf0f465175ae540..4d7e89067c22d663140397309874cb53d8740f29 100644 --- a/vendor/google.golang.org/grpc/transport/transport.go +++ b/vendor/google.golang.org/grpc/internal/transport/transport.go @@ -19,9 +19,10 @@ // Package transport defines and implements message oriented communication // channel to complete various transactions (e.g., an RPC). It is meant for // grpc-internal usage and is not intended to be imported directly by users. -package transport // externally used as import "google.golang.org/grpc/transport" +package transport import ( + "context" "errors" "fmt" "io" @@ -29,7 +30,6 @@ import ( "sync" "sync/atomic" - "golang.org/x/net/context" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/keepalive" @@ -176,7 +176,6 @@ type Stream struct { buf *recvBuffer trReader io.Reader fc *inFlow - recvQuota uint32 wq *writeQuota // Callback to state application's intentions to read data. This @@ -187,10 +186,16 @@ type Stream struct { headerDone uint32 // set when headerChan is closed. Used to avoid closing headerChan multiple times. // hdrMu protects header and trailer metadata on the server-side. - hdrMu sync.Mutex - header metadata.MD // the received header metadata. + hdrMu sync.Mutex + // On client side, header keeps the received header metadata. + // + // On server side, header keeps the header set by SetHeader(). The complete + // header will merged into this after t.WriteHeader() is called. + header metadata.MD trailer metadata.MD // the key-value map of trailer metadata. + noHeaders bool // set if the client never received headers (set only after the stream is done). + // On the server-side, headerSent is atomically set to 1 when the headers are sent out. headerSent uint32 @@ -259,16 +264,25 @@ func (s *Stream) SetSendCompress(str string) { s.sendCompress = str } -// Done returns a chanel which is closed when it receives the final status +// Done returns a channel which is closed when it receives the final status // from the server. func (s *Stream) Done() <-chan struct{} { return s.done } -// Header acquires the key-value pairs of header metadata once it -// is available. It blocks until i) the metadata is ready or ii) there is no -// header metadata or iii) the stream is canceled/expired. +// Header returns the header metadata of the stream. +// +// On client side, it acquires the key-value pairs of header metadata once it is +// available. It blocks until i) the metadata is ready or ii) there is no header +// metadata or iii) the stream is canceled/expired. +// +// On server side, it returns the out header after t.WriteHeader is called. func (s *Stream) Header() (metadata.MD, error) { + if s.headerChan == nil && s.header != nil { + // On server side, return the header in stream. It will be the out + // header after t.WriteHeader is called. + return s.header.Copy(), nil + } err := s.waitOnHeader() // Even if the stream is closed, header is returned if available. select { @@ -282,6 +296,19 @@ func (s *Stream) Header() (metadata.MD, error) { return nil, err } +// TrailersOnly blocks until a header or trailers-only frame is received and +// then returns true if the stream was trailers-only. If the stream ends +// before headers are received, returns true, nil. If a context error happens +// first, returns it as a status error. Client-side only. +func (s *Stream) TrailersOnly() (bool, error) { + err := s.waitOnHeader() + if err != nil { + return false, err + } + // if !headerDone, some other connection error occurred. + return s.noHeaders && atomic.LoadUint32(&s.headerDone) == 1, nil +} + // Trailer returns the cached trailer metedata. Note that if it is not called // after the entire stream is done, it could return an empty MD. Client // side only. @@ -292,12 +319,6 @@ func (s *Stream) Trailer() metadata.MD { return c } -// ServerTransport returns the underlying ServerTransport for the stream. -// The client side stream always returns nil. -func (s *Stream) ServerTransport() ServerTransport { - return s.st -} - // ContentSubtype returns the content-subtype for a request. For example, a // content-subtype of "proto" will result in a content-type of // "application/grpc+proto". This will always be lowercase. See @@ -319,7 +340,7 @@ func (s *Stream) Method() string { // Status returns the status received from the server. // Status can be read safely only after the stream has ended, -// that is, read or write has returned io.EOF. +// that is, after Done() is closed. func (s *Stream) Status() *status.Status { return s.status } @@ -344,8 +365,7 @@ func (s *Stream) SetHeader(md metadata.MD) error { // combined with any metadata set by previous calls to SetHeader and // then written to the transport stream. func (s *Stream) SendHeader(md metadata.MD) error { - t := s.ServerTransport() - return t.WriteHeader(s, md) + return s.st.WriteHeader(s, md) } // SetTrailer sets the trailer metadata which will be sent with the RPC status @@ -439,6 +459,7 @@ type ServerConfig struct { WriteBufferSize int ReadBufferSize int ChannelzParentID int64 + MaxHeaderListSize *uint32 } // NewServerTransport creates a ServerTransport with conn or non-nil error @@ -451,17 +472,18 @@ func NewServerTransport(protocol string, conn net.Conn, config *ServerConfig) (S type ConnectOptions struct { // UserAgent is the application user agent. UserAgent string - // Authority is the :authority pseudo-header to use. This field has no effect if - // TransportCredentials is set. - Authority string // Dialer specifies how to dial a network address. Dialer func(context.Context, string) (net.Conn, error) // FailOnNonTempDialError specifies if gRPC fails on non-temporary dial errors. FailOnNonTempDialError bool // PerRPCCredentials stores the PerRPCCredentials required to issue RPCs. PerRPCCredentials []credentials.PerRPCCredentials - // TransportCredentials stores the Authenticator required to setup a client connection. + // TransportCredentials stores the Authenticator required to setup a client + // connection. Only one of TransportCredentials and CredsBundle is non-nil. TransportCredentials credentials.TransportCredentials + // CredsBundle is the credentials bundle to be used. Only one of + // TransportCredentials and CredsBundle is non-nil. + CredsBundle credentials.Bundle // KeepaliveParams stores the keepalive parameters. KeepaliveParams keepalive.ClientParameters // StatsHandler stores the handler for stats. @@ -476,6 +498,8 @@ type ConnectOptions struct { ReadBufferSize int // ChannelzParentID sets the addrConn id which initiate the creation of this client transport. ChannelzParentID int64 + // MaxHeaderListSize sets the max (uncompressed) size of header list that is prepared to be received. + MaxHeaderListSize *uint32 } // TargetInfo contains the information of the target such as network address and metadata. @@ -487,8 +511,8 @@ type TargetInfo struct { // NewClientTransport establishes the transport with the required ConnectOptions // and returns it to the caller. -func NewClientTransport(connectCtx, ctx context.Context, target TargetInfo, opts ConnectOptions, onSuccess func()) (ClientTransport, error) { - return newHTTP2Client(connectCtx, ctx, target, opts, onSuccess) +func NewClientTransport(connectCtx, ctx context.Context, target TargetInfo, opts ConnectOptions, onSuccess func(), onGoAway func(GoAwayReason), onClose func()) (ClientTransport, error) { + return newHTTP2Client(connectCtx, ctx, target, opts, onSuccess, onGoAway, onClose) } // Options provides additional hints and information for message @@ -497,11 +521,6 @@ type Options struct { // Last indicates whether this write is the last piece for // this stream. Last bool - - // Delay is a hint to the transport implementation for whether - // the data could be buffered for a batching write. The - // transport implementation may ignore the hint. - Delay bool } // CallHdr carries the information of a particular RPC. @@ -519,14 +538,6 @@ type CallHdr struct { // Creds specifies credentials.PerRPCCredentials for a call. Creds credentials.PerRPCCredentials - // Flush indicates whether a new stream command should be sent - // to the peer without waiting for the first data. This is - // only a hint. - // If it's true, the transport may modify the flush decision - // for performance purposes. - // If it's false, new stream will never be flushed. - Flush bool - // ContentSubtype specifies the content-subtype for a request. For example, a // content-subtype of "proto" will result in a content-type of // "application/grpc+proto". The value of ContentSubtype must be all @@ -534,6 +545,8 @@ type CallHdr struct { // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests // for more details. ContentSubtype string + + PreviousAttempts int // value of grpc-previous-rpc-attempts header to set } // ClientTransport is the common interface for all gRPC client-side transport @@ -622,14 +635,6 @@ type ServerTransport interface { IncrMsgRecv() } -// streamErrorf creates an StreamError with the specified error code and description. -func streamErrorf(c codes.Code, format string, a ...interface{}) StreamError { - return StreamError{ - Code: c, - Desc: fmt.Sprintf(format, a...), - } -} - // connectionErrorf creates an ConnectionError with the specified error description. func connectionErrorf(temp bool, e error, format string, a ...interface{}) ConnectionError { return ConnectionError{ @@ -672,7 +677,7 @@ var ( // errStreamDrain indicates that the stream is rejected because the // connection is draining. This could be caused by goaway or balancer // removing the address. - errStreamDrain = streamErrorf(codes.Unavailable, "the connection is draining") + errStreamDrain = status.Error(codes.Unavailable, "the connection is draining") // errStreamDone is returned from write at the client side to indiacte application // layer of an error. errStreamDone = errors.New("the stream is done") @@ -681,18 +686,6 @@ var ( statusGoAway = status.New(codes.Unavailable, "the stream is rejected because server is draining the connection") ) -// TODO: See if we can replace StreamError with status package errors. - -// StreamError is an error that only affects one stream within a connection. -type StreamError struct { - Code codes.Code - Desc string -} - -func (e StreamError) Error() string { - return fmt.Sprintf("stream error: code = %s desc = %q", e.Code, e.Desc) -} - // GoAwayReason contains the reason for the GoAway frame received. type GoAwayReason uint8 @@ -706,3 +699,38 @@ const ( // "too_many_pings". GoAwayTooManyPings GoAwayReason = 2 ) + +// channelzData is used to store channelz related data for http2Client and http2Server. +// These fields cannot be embedded in the original structs (e.g. http2Client), since to do atomic +// operation on int64 variable on 32-bit machine, user is responsible to enforce memory alignment. +// Here, by grouping those int64 fields inside a struct, we are enforcing the alignment. +type channelzData struct { + kpCount int64 + // The number of streams that have started, including already finished ones. + streamsStarted int64 + // Client side: The number of streams that have ended successfully by receiving + // EoS bit set frame from server. + // Server side: The number of streams that have ended successfully by sending + // frame with EoS bit set. + streamsSucceeded int64 + streamsFailed int64 + // lastStreamCreatedTime stores the timestamp that the last stream gets created. It is of int64 type + // instead of time.Time since it's more costly to atomically update time.Time variable than int64 + // variable. The same goes for lastMsgSentTime and lastMsgRecvTime. + lastStreamCreatedTime int64 + msgSent int64 + msgRecv int64 + lastMsgSentTime int64 + lastMsgRecvTime int64 +} + +// ContextErr converts the error from context package into a status error. +func ContextErr(err error) error { + switch err { + case context.DeadlineExceeded: + return status.Error(codes.DeadlineExceeded, err.Error()) + case context.Canceled: + return status.Error(codes.Canceled, err.Error()) + } + return status.Errorf(codes.Internal, "Unexpected error from context packet: %v", err) +} diff --git a/vendor/google.golang.org/grpc/transport/transport_test.go b/vendor/google.golang.org/grpc/internal/transport/transport_test.go similarity index 83% rename from vendor/google.golang.org/grpc/transport/transport_test.go rename to vendor/google.golang.org/grpc/internal/transport/transport_test.go index b6add205d9647af0c5574d09a954bfa5c8b5bd28..91b6b95fae8e3221318d3c62b3acb274a2e5bb3e 100644 --- a/vendor/google.golang.org/grpc/transport/transport_test.go +++ b/vendor/google.golang.org/grpc/internal/transport/transport_test.go @@ -21,6 +21,7 @@ package transport import ( "bufio" "bytes" + "context" "encoding/binary" "errors" "fmt" @@ -36,11 +37,11 @@ import ( "testing" "time" - "golang.org/x/net/context" "golang.org/x/net/http2" "golang.org/x/net/http2/hpack" "google.golang.org/grpc/codes" "google.golang.org/grpc/internal/leakcheck" + "google.golang.org/grpc/internal/syscall" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/status" ) @@ -140,9 +141,9 @@ func (h *testStreamHandler) handleStreamPingPong(t *testing.T, s *Stream) { } func (h *testStreamHandler) handleStreamMisbehave(t *testing.T, s *Stream) { - conn, ok := s.ServerTransport().(*http2Server) + conn, ok := s.st.(*http2Server) if !ok { - t.Fatalf("Failed to convert %v to *http2Server", s.ServerTransport()) + t.Fatalf("Failed to convert %v to *http2Server", s.st) } var sent int p := make([]byte, http2MaxFrameLen) @@ -396,30 +397,26 @@ func setUpServerOnly(t *testing.T, port int, serverConfig *ServerConfig, ht hTyp return server } -func setUp(t *testing.T, port int, maxStreams uint32, ht hType) (*server, ClientTransport) { - return setUpWithOptions(t, port, &ServerConfig{MaxStreams: maxStreams}, ht, ConnectOptions{}, func() {}) +func setUp(t *testing.T, port int, maxStreams uint32, ht hType) (*server, *http2Client, func()) { + return setUpWithOptions(t, port, &ServerConfig{MaxStreams: maxStreams}, ht, ConnectOptions{}) } -func setUpWithOptions(t *testing.T, port int, serverConfig *ServerConfig, ht hType, copts ConnectOptions, onHandshake func()) (*server, ClientTransport) { +func setUpWithOptions(t *testing.T, port int, serverConfig *ServerConfig, ht hType, copts ConnectOptions) (*server, *http2Client, func()) { server := setUpServerOnly(t, port, serverConfig, ht) addr := "localhost:" + server.port - var ( - ct ClientTransport - connErr error - ) target := TargetInfo{ Addr: addr, } connectCtx, cancel := context.WithDeadline(context.Background(), time.Now().Add(2*time.Second)) - ct, connErr = NewClientTransport(connectCtx, context.Background(), target, copts, onHandshake) + ct, connErr := NewClientTransport(connectCtx, context.Background(), target, copts, func() {}, func(GoAwayReason) {}, func() {}) if connErr != nil { cancel() // Do not cancel in success path. t.Fatalf("failed to create transport: %v", connErr) } - return server, ct + return server, ct.(*http2Client), cancel } -func setUpWithNoPingServer(t *testing.T, copts ConnectOptions, done chan net.Conn) ClientTransport { +func setUpWithNoPingServer(t *testing.T, copts ConnectOptions, done chan net.Conn) (*http2Client, func()) { lis, err := net.Listen("tcp", "localhost:0") if err != nil { t.Fatalf("Failed to listen: %v", err) @@ -436,7 +433,7 @@ func setUpWithNoPingServer(t *testing.T, copts ConnectOptions, done chan net.Con done <- conn }() connectCtx, cancel := context.WithDeadline(context.Background(), time.Now().Add(2*time.Second)) - tr, err := NewClientTransport(connectCtx, context.Background(), TargetInfo{Addr: lis.Addr().String()}, copts, func() {}) + tr, err := NewClientTransport(connectCtx, context.Background(), TargetInfo{Addr: lis.Addr().String()}, copts, func() {}, func(GoAwayReason) {}, func() {}) if err != nil { cancel() // Do not cancel in success path. // Server clean-up. @@ -446,14 +443,15 @@ func setUpWithNoPingServer(t *testing.T, copts ConnectOptions, done chan net.Con } t.Fatalf("Failed to dial: %v", err) } - return tr + return tr.(*http2Client), cancel } // TestInflightStreamClosing ensures that closing in-flight stream -// sends StreamError to concurrent stream reader. +// sends status error to concurrent stream reader. func TestInflightStreamClosing(t *testing.T) { serverConfig := &ServerConfig{} - server, client := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}, func() {}) + server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}) + defer cancel() defer server.stop() defer client.Close() @@ -463,7 +461,7 @@ func TestInflightStreamClosing(t *testing.T) { } donec := make(chan struct{}) - serr := StreamError{Desc: "client connection is closing"} + serr := status.Error(codes.Internal, "client connection is closing") go func() { defer close(donec) if _, err := stream.Read(make([]byte, defaultWindowSize)); err != serr { @@ -482,7 +480,7 @@ func TestInflightStreamClosing(t *testing.T) { <-timeout.C } case <-timeout.C: - t.Fatalf("Test timed out, expected a StreamError.") + t.Fatalf("Test timed out, expected a status error.") } } @@ -495,14 +493,15 @@ func TestMaxConnectionIdle(t *testing.T) { MaxConnectionIdle: 2 * time.Second, }, } - server, client := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}, func() {}) + server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}) + defer cancel() defer server.stop() defer client.Close() - stream, err := client.NewStream(context.Background(), &CallHdr{Flush: true}) + stream, err := client.NewStream(context.Background(), &CallHdr{}) if err != nil { t.Fatalf("Client failed to create RPC request: %v", err) } - client.(*http2Client).closeStream(stream, io.EOF, true, http2.ErrCodeCancel, nil, nil, false) + client.closeStream(stream, io.EOF, true, http2.ErrCodeCancel, nil, nil, false) // wait for server to see that closed stream and max-age logic to send goaway after no new RPCs are mode timeout := time.NewTimer(time.Second * 4) select { @@ -522,10 +521,11 @@ func TestMaxConnectionIdleNegative(t *testing.T) { MaxConnectionIdle: 2 * time.Second, }, } - server, client := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}, func() {}) + server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}) + defer cancel() defer server.stop() defer client.Close() - _, err := client.NewStream(context.Background(), &CallHdr{Flush: true}) + _, err := client.NewStream(context.Background(), &CallHdr{}) if err != nil { t.Fatalf("Client failed to create RPC request: %v", err) } @@ -548,7 +548,8 @@ func TestMaxConnectionAge(t *testing.T) { MaxConnectionAge: 2 * time.Second, }, } - server, client := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}, func() {}) + server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}) + defer cancel() defer server.stop() defer client.Close() _, err := client.NewStream(context.Background(), &CallHdr{}) @@ -567,6 +568,11 @@ func TestMaxConnectionAge(t *testing.T) { } } +const ( + defaultWriteBufSize = 32 * 1024 + defaultReadBufSize = 32 * 1024 +) + // TestKeepaliveServer tests that a server closes connection with a client that doesn't respond to keepalive pings. func TestKeepaliveServer(t *testing.T) { serverConfig := &ServerConfig{ @@ -575,7 +581,8 @@ func TestKeepaliveServer(t *testing.T) { Timeout: 1 * time.Second, }, } - server, c := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}, func() {}) + server, c, cancel := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}) + defer cancel() defer server.stop() defer c.Close() client, err := net.Dial("tcp", server.lis.Addr().String()) @@ -590,7 +597,7 @@ func TestKeepaliveServer(t *testing.T) { if n, err := client.Write(clientPreface); err != nil || n != len(clientPreface) { t.Fatalf("Error writing client preface; n=%v, err=%v", n, err) } - framer := newFramer(client, defaultWriteBufSize, defaultReadBufSize) + framer := newFramer(client, defaultWriteBufSize, defaultReadBufSize, 0) if err := framer.fr.WriteSettings(http2.Setting{}); err != nil { t.Fatal("Error writing settings frame:", err) } @@ -618,27 +625,28 @@ func TestKeepaliveServerNegative(t *testing.T) { Timeout: 1 * time.Second, }, } - server, client := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}, func() {}) + server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}) + defer cancel() defer server.stop() defer client.Close() // Give keepalive logic some time by sleeping. time.Sleep(4 * time.Second) // Assert that client is still active. - clientTr := client.(*http2Client) - clientTr.mu.Lock() - defer clientTr.mu.Unlock() - if clientTr.state != reachable { + client.mu.Lock() + defer client.mu.Unlock() + if client.state != reachable { t.Fatalf("Test failed: Expected server-client connection to be healthy.") } } func TestKeepaliveClientClosesIdleTransport(t *testing.T) { done := make(chan net.Conn, 1) - tr := setUpWithNoPingServer(t, ConnectOptions{KeepaliveParams: keepalive.ClientParameters{ + tr, cancel := setUpWithNoPingServer(t, ConnectOptions{KeepaliveParams: keepalive.ClientParameters{ Time: 2 * time.Second, // Keepalive time = 2 sec. Timeout: 1 * time.Second, // Keepalive timeout = 1 sec. PermitWithoutStream: true, // Run keepalive even with no RPCs. }}, done) + defer cancel() defer tr.Close() conn, ok := <-done if !ok { @@ -648,20 +656,20 @@ func TestKeepaliveClientClosesIdleTransport(t *testing.T) { // Sleep for keepalive to close the connection. time.Sleep(4 * time.Second) // Assert that the connection was closed. - ct := tr.(*http2Client) - ct.mu.Lock() - defer ct.mu.Unlock() - if ct.state == reachable { + tr.mu.Lock() + defer tr.mu.Unlock() + if tr.state == reachable { t.Fatalf("Test Failed: Expected client transport to have closed.") } } func TestKeepaliveClientStaysHealthyOnIdleTransport(t *testing.T) { done := make(chan net.Conn, 1) - tr := setUpWithNoPingServer(t, ConnectOptions{KeepaliveParams: keepalive.ClientParameters{ + tr, cancel := setUpWithNoPingServer(t, ConnectOptions{KeepaliveParams: keepalive.ClientParameters{ Time: 2 * time.Second, // Keepalive time = 2 sec. Timeout: 1 * time.Second, // Keepalive timeout = 1 sec. }}, done) + defer cancel() defer tr.Close() conn, ok := <-done if !ok { @@ -671,20 +679,20 @@ func TestKeepaliveClientStaysHealthyOnIdleTransport(t *testing.T) { // Give keepalive some time. time.Sleep(4 * time.Second) // Assert that connections is still healthy. - ct := tr.(*http2Client) - ct.mu.Lock() - defer ct.mu.Unlock() - if ct.state != reachable { + tr.mu.Lock() + defer tr.mu.Unlock() + if tr.state != reachable { t.Fatalf("Test failed: Expected client transport to be healthy.") } } func TestKeepaliveClientClosesWithActiveStreams(t *testing.T) { done := make(chan net.Conn, 1) - tr := setUpWithNoPingServer(t, ConnectOptions{KeepaliveParams: keepalive.ClientParameters{ + tr, cancel := setUpWithNoPingServer(t, ConnectOptions{KeepaliveParams: keepalive.ClientParameters{ Time: 2 * time.Second, // Keepalive time = 2 sec. Timeout: 1 * time.Second, // Keepalive timeout = 1 sec. }}, done) + defer cancel() defer tr.Close() conn, ok := <-done if !ok { @@ -692,36 +700,35 @@ func TestKeepaliveClientClosesWithActiveStreams(t *testing.T) { } defer conn.Close() // Create a stream. - _, err := tr.NewStream(context.Background(), &CallHdr{Flush: true}) + _, err := tr.NewStream(context.Background(), &CallHdr{}) if err != nil { t.Fatalf("Failed to create a new stream: %v", err) } // Give keepalive some time. time.Sleep(4 * time.Second) // Assert that transport was closed. - ct := tr.(*http2Client) - ct.mu.Lock() - defer ct.mu.Unlock() - if ct.state == reachable { + tr.mu.Lock() + defer tr.mu.Unlock() + if tr.state == reachable { t.Fatalf("Test failed: Expected client transport to have closed.") } } func TestKeepaliveClientStaysHealthyWithResponsiveServer(t *testing.T) { - s, tr := setUpWithOptions(t, 0, &ServerConfig{MaxStreams: math.MaxUint32}, normal, ConnectOptions{KeepaliveParams: keepalive.ClientParameters{ + s, tr, cancel := setUpWithOptions(t, 0, &ServerConfig{MaxStreams: math.MaxUint32}, normal, ConnectOptions{KeepaliveParams: keepalive.ClientParameters{ Time: 2 * time.Second, // Keepalive time = 2 sec. Timeout: 1 * time.Second, // Keepalive timeout = 1 sec. PermitWithoutStream: true, // Run keepalive even with no RPCs. - }}, func() {}) + }}) + defer cancel() defer s.stop() defer tr.Close() // Give keep alive some time. time.Sleep(4 * time.Second) // Assert that transport is healthy. - ct := tr.(*http2Client) - ct.mu.Lock() - defer ct.mu.Unlock() - if ct.state != reachable { + tr.mu.Lock() + defer tr.mu.Unlock() + if tr.state != reachable { t.Fatalf("Test failed: Expected client transport to be healthy.") } } @@ -739,7 +746,8 @@ func TestKeepaliveServerEnforcementWithAbusiveClientNoRPC(t *testing.T) { PermitWithoutStream: true, }, } - server, client := setUpWithOptions(t, 0, serverConfig, normal, clientOptions, func() {}) + server, client, cancel := setUpWithOptions(t, 0, serverConfig, normal, clientOptions) + defer cancel() defer server.stop() defer client.Close() @@ -753,10 +761,9 @@ func TestKeepaliveServerEnforcementWithAbusiveClientNoRPC(t *testing.T) { t.Fatalf("Test failed: Expected a GoAway from server.") } time.Sleep(500 * time.Millisecond) - ct := client.(*http2Client) - ct.mu.Lock() - defer ct.mu.Unlock() - if ct.state == reachable { + client.mu.Lock() + defer client.mu.Unlock() + if client.state == reachable { t.Fatalf("Test failed: Expected the connection to be closed.") } } @@ -773,11 +780,12 @@ func TestKeepaliveServerEnforcementWithAbusiveClientWithRPC(t *testing.T) { Timeout: 1 * time.Second, }, } - server, client := setUpWithOptions(t, 0, serverConfig, suspended, clientOptions, func() {}) + server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, clientOptions) + defer cancel() defer server.stop() defer client.Close() - if _, err := client.NewStream(context.Background(), &CallHdr{Flush: true}); err != nil { + if _, err := client.NewStream(context.Background(), &CallHdr{}); err != nil { t.Fatalf("Client failed to create stream.") } timeout := time.NewTimer(10 * time.Second) @@ -790,10 +798,9 @@ func TestKeepaliveServerEnforcementWithAbusiveClientWithRPC(t *testing.T) { t.Fatalf("Test failed: Expected a GoAway from server.") } time.Sleep(500 * time.Millisecond) - ct := client.(*http2Client) - ct.mu.Lock() - defer ct.mu.Unlock() - if ct.state == reachable { + client.mu.Lock() + defer client.mu.Unlock() + if client.state == reachable { t.Fatalf("Test failed: Expected the connection to be closed.") } } @@ -812,17 +819,17 @@ func TestKeepaliveServerEnforcementWithObeyingClientNoRPC(t *testing.T) { PermitWithoutStream: true, }, } - server, client := setUpWithOptions(t, 0, serverConfig, normal, clientOptions, func() {}) + server, client, cancel := setUpWithOptions(t, 0, serverConfig, normal, clientOptions) + defer cancel() defer server.stop() defer client.Close() // Give keepalive enough time. time.Sleep(3 * time.Second) // Assert that connection is healthy. - ct := client.(*http2Client) - ct.mu.Lock() - defer ct.mu.Unlock() - if ct.state != reachable { + client.mu.Lock() + defer client.mu.Unlock() + if client.state != reachable { t.Fatalf("Test failed: Expected connection to be healthy.") } } @@ -839,27 +846,28 @@ func TestKeepaliveServerEnforcementWithObeyingClientWithRPC(t *testing.T) { Timeout: 1 * time.Second, }, } - server, client := setUpWithOptions(t, 0, serverConfig, suspended, clientOptions, func() {}) + server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, clientOptions) + defer cancel() defer server.stop() defer client.Close() - if _, err := client.NewStream(context.Background(), &CallHdr{Flush: true}); err != nil { + if _, err := client.NewStream(context.Background(), &CallHdr{}); err != nil { t.Fatalf("Client failed to create stream.") } // Give keepalive enough time. time.Sleep(3 * time.Second) // Assert that connection is healthy. - ct := client.(*http2Client) - ct.mu.Lock() - defer ct.mu.Unlock() - if ct.state != reachable { + client.mu.Lock() + defer client.mu.Unlock() + if client.state != reachable { t.Fatalf("Test failed: Expected connection to be healthy.") } } func TestClientSendAndReceive(t *testing.T) { - server, ct := setUp(t, 0, math.MaxUint32, normal) + server, ct, cancel := setUp(t, 0, math.MaxUint32, normal) + defer cancel() callHdr := &CallHdr{ Host: "localhost", Method: "foo.Small", @@ -878,10 +886,7 @@ func TestClientSendAndReceive(t *testing.T) { if s2.id != 3 { t.Fatalf("wrong stream id: %d", s2.id) } - opts := Options{ - Last: true, - Delay: false, - } + opts := Options{Last: true} if err := ct.Write(s1, nil, expectedRequest, &opts); err != nil && err != io.EOF { t.Fatalf("failed to send data: %v", err) } @@ -899,7 +904,8 @@ func TestClientSendAndReceive(t *testing.T) { } func TestClientErrorNotify(t *testing.T) { - server, ct := setUp(t, 0, math.MaxUint32, normal) + server, ct, cancel := setUp(t, 0, math.MaxUint32, normal) + defer cancel() go server.stop() // ct.reader should detect the error and activate ct.Error(). <-ct.Error() @@ -915,10 +921,7 @@ func performOneRPC(ct ClientTransport) { if err != nil { return } - opts := Options{ - Last: true, - Delay: false, - } + opts := Options{Last: true} if err := ct.Write(s, []byte{}, expectedRequest, &opts); err == nil || err == io.EOF { time.Sleep(5 * time.Millisecond) // The following s.Recv()'s could error out because the @@ -933,7 +936,8 @@ func performOneRPC(ct ClientTransport) { } func TestClientMix(t *testing.T) { - s, ct := setUp(t, 0, math.MaxUint32, normal) + s, ct, cancel := setUp(t, 0, math.MaxUint32, normal) + defer cancel() go func(s *server) { time.Sleep(5 * time.Second) s.stop() @@ -949,7 +953,8 @@ func TestClientMix(t *testing.T) { } func TestLargeMessage(t *testing.T) { - server, ct := setUp(t, 0, math.MaxUint32, normal) + server, ct, cancel := setUp(t, 0, math.MaxUint32, normal) + defer cancel() callHdr := &CallHdr{ Host: "localhost", Method: "foo.Large", @@ -963,7 +968,7 @@ func TestLargeMessage(t *testing.T) { if err != nil { t.Errorf("%v.NewStream(_, _) = _, %v, want _, ", ct, err) } - if err := ct.Write(s, []byte{}, expectedRequestLarge, &Options{Last: true, Delay: false}); err != nil && err != io.EOF { + if err := ct.Write(s, []byte{}, expectedRequestLarge, &Options{Last: true}); err != nil && err != io.EOF { t.Errorf("%v.Write(_, _, _) = %v, want ", ct, err) } p := make([]byte, len(expectedResponseLarge)) @@ -990,7 +995,8 @@ func TestLargeMessageWithDelayRead(t *testing.T) { InitialWindowSize: defaultWindowSize, InitialConnWindowSize: defaultWindowSize, } - server, ct := setUpWithOptions(t, 0, sc, delayRead, co, func() {}) + server, ct, cancel := setUpWithOptions(t, 0, sc, delayRead, co) + defer cancel() defer server.stop() defer ct.Close() server.mu.Lock() @@ -1077,7 +1083,8 @@ func TestLargeMessageWithDelayRead(t *testing.T) { } func TestGracefulClose(t *testing.T) { - server, ct := setUp(t, 0, math.MaxUint32, pingpong) + server, ct, cancel := setUp(t, 0, math.MaxUint32, pingpong) + defer cancel() defer func() { // Stop the server's listener to make the server's goroutines terminate // (after the last active stream is done). @@ -1141,7 +1148,8 @@ func TestGracefulClose(t *testing.T) { } func TestLargeMessageSuspension(t *testing.T) { - server, ct := setUp(t, 0, math.MaxUint32, suspended) + server, ct, cancel := setUp(t, 0, math.MaxUint32, suspended) + defer cancel() callHdr := &CallHdr{ Host: "localhost", Method: "foo.Large", @@ -1166,8 +1174,8 @@ func TestLargeMessageSuspension(t *testing.T) { if err != errStreamDone { t.Fatalf("Write got %v, want io.EOF", err) } - expectedErr := streamErrorf(codes.DeadlineExceeded, "%v", context.DeadlineExceeded) - if _, err := s.Read(make([]byte, 8)); err != expectedErr { + expectedErr := status.Error(codes.DeadlineExceeded, context.DeadlineExceeded.Error()) + if _, err := s.Read(make([]byte, 8)); err.Error() != expectedErr.Error() { t.Fatalf("Read got %v of type %T, want %v", err, err, expectedErr) } ct.Close() @@ -1178,7 +1186,8 @@ func TestMaxStreams(t *testing.T) { serverConfig := &ServerConfig{ MaxStreams: 1, } - server, ct := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}, func() {}) + server, ct, cancel := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}) + defer cancel() defer ct.Close() defer server.stop() callHdr := &CallHdr{ @@ -1195,7 +1204,7 @@ func TestMaxStreams(t *testing.T) { pctx, cancel := context.WithCancel(context.Background()) defer cancel() timer := time.NewTimer(time.Second * 10) - expectedErr := streamErrorf(codes.DeadlineExceeded, "%v", context.DeadlineExceeded) + expectedErr := status.Error(codes.DeadlineExceeded, context.DeadlineExceeded.Error()) for { select { case <-timer.C: @@ -1209,7 +1218,7 @@ func TestMaxStreams(t *testing.T) { if str, err := ct.NewStream(ctx, callHdr); err == nil { slist = append(slist, str) continue - } else if err != expectedErr { + } else if err.Error() != expectedErr.Error() { t.Fatalf("ct.NewStream(_,_) = _, %v, want _, %v", err, expectedErr) } timer.Stop() @@ -1238,15 +1247,15 @@ func TestMaxStreams(t *testing.T) { ct.CloseStream(s, nil) <-done ct.Close() - cc := ct.(*http2Client) - <-cc.writerDone - if cc.maxConcurrentStreams != 1 { - t.Fatalf("cc.maxConcurrentStreams: %d, want 1", cc.maxConcurrentStreams) + <-ct.writerDone + if ct.maxConcurrentStreams != 1 { + t.Fatalf("ct.maxConcurrentStreams: %d, want 1", ct.maxConcurrentStreams) } } func TestServerContextCanceledOnClosedConnection(t *testing.T) { - server, ct := setUp(t, 0, math.MaxUint32, suspended) + server, ct, cancel := setUp(t, 0, math.MaxUint32, suspended) + defer cancel() callHdr := &CallHdr{ Host: "localhost", Method: "foo", @@ -1270,15 +1279,11 @@ func TestServerContextCanceledOnClosedConnection(t *testing.T) { server.mu.Unlock() break } - cc, ok := ct.(*http2Client) - if !ok { - t.Fatalf("Failed to convert %v to *http2Client", ct) - } s, err := ct.NewStream(context.Background(), callHdr) if err != nil { t.Fatalf("Failed to open stream: %v", err) } - cc.controlBuf.put(&dataFrame{ + ct.controlBuf.put(&dataFrame{ streamID: s.id, endStream: false, h: nil, @@ -1298,7 +1303,7 @@ func TestServerContextCanceledOnClosedConnection(t *testing.T) { sc.mu.Unlock() break } - cc.Close() + ct.Close() select { case <-ss.Context().Done(): if ss.Context().Err() != context.Canceled { @@ -1315,7 +1320,8 @@ func TestClientConnDecoupledFromApplicationRead(t *testing.T) { InitialWindowSize: defaultWindowSize, InitialConnWindowSize: defaultWindowSize, } - server, client := setUpWithOptions(t, 0, &ServerConfig{}, notifyCall, connectOptions, func() {}) + server, client, cancel := setUpWithOptions(t, 0, &ServerConfig{}, notifyCall, connectOptions) + defer cancel() defer server.stop() defer client.Close() @@ -1337,7 +1343,7 @@ func TestClientConnDecoupledFromApplicationRead(t *testing.T) { notifyChan := make(chan struct{}) server.h.notify = notifyChan server.mu.Unlock() - cstream1, err := client.NewStream(context.Background(), &CallHdr{Flush: true}) + cstream1, err := client.NewStream(context.Background(), &CallHdr{}) if err != nil { t.Fatalf("Client failed to create first stream. Err: %v", err) } @@ -1364,7 +1370,7 @@ func TestClientConnDecoupledFromApplicationRead(t *testing.T) { server.h.notify = notifyChan server.mu.Unlock() // Create another stream on client. - cstream2, err := client.NewStream(context.Background(), &CallHdr{Flush: true}) + cstream2, err := client.NewStream(context.Background(), &CallHdr{}) if err != nil { t.Fatalf("Client failed to create second stream. Err: %v", err) } @@ -1401,7 +1407,8 @@ func TestServerConnDecoupledFromApplicationRead(t *testing.T) { InitialWindowSize: defaultWindowSize, InitialConnWindowSize: defaultWindowSize, } - server, client := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}, func() {}) + server, client, cancel := setUpWithOptions(t, 0, serverConfig, suspended, ConnectOptions{}) + defer cancel() defer server.stop() defer client.Close() waitWhileTrue(t, func() (bool, error) { @@ -1419,7 +1426,7 @@ func TestServerConnDecoupledFromApplicationRead(t *testing.T) { st = k.(*http2Server) } server.mu.Unlock() - cstream1, err := client.NewStream(context.Background(), &CallHdr{Flush: true}) + cstream1, err := client.NewStream(context.Background(), &CallHdr{}) if err != nil { t.Fatalf("Failed to create 1st stream. Err: %v", err) } @@ -1428,7 +1435,7 @@ func TestServerConnDecoupledFromApplicationRead(t *testing.T) { t.Fatalf("Client failed to write data. Err: %v", err) } //Client should be able to create another stream and send data on it. - cstream2, err := client.NewStream(context.Background(), &CallHdr{Flush: true}) + cstream2, err := client.NewStream(context.Background(), &CallHdr{}) if err != nil { t.Fatalf("Failed to create 2nd stream. Err: %v", err) } @@ -1630,7 +1637,7 @@ func TestClientWithMisbehavedServer(t *testing.T) { }() connectCtx, cancel := context.WithDeadline(context.Background(), time.Now().Add(2*time.Second)) defer cancel() - ct, err := NewClientTransport(connectCtx, context.Background(), TargetInfo{Addr: lis.Addr().String()}, ConnectOptions{}, func() {}) + ct, err := NewClientTransport(connectCtx, context.Background(), TargetInfo{Addr: lis.Addr().String()}, ConnectOptions{}, func() {}, func(GoAwayReason) {}, func() {}) if err != nil { t.Fatalf("Error while creating client transport: %v", err) } @@ -1654,7 +1661,8 @@ func TestClientWithMisbehavedServer(t *testing.T) { var encodingTestStatus = status.New(codes.Internal, "\n") func TestEncodingRequiredStatus(t *testing.T) { - server, ct := setUp(t, 0, math.MaxUint32, encodingRequiredStatus) + server, ct, cancel := setUp(t, 0, math.MaxUint32, encodingRequiredStatus) + defer cancel() callHdr := &CallHdr{ Host: "localhost", Method: "foo", @@ -1663,10 +1671,7 @@ func TestEncodingRequiredStatus(t *testing.T) { if err != nil { return } - opts := Options{ - Last: true, - Delay: false, - } + opts := Options{Last: true} if err := ct.Write(s, nil, expectedRequest, &opts); err != nil && err != errStreamDone { t.Fatalf("Failed to write the request: %v", err) } @@ -1682,7 +1687,8 @@ func TestEncodingRequiredStatus(t *testing.T) { } func TestInvalidHeaderField(t *testing.T) { - server, ct := setUp(t, 0, math.MaxUint32, invalidHeaderField) + server, ct, cancel := setUp(t, 0, math.MaxUint32, invalidHeaderField) + defer cancel() callHdr := &CallHdr{ Host: "localhost", Method: "foo", @@ -1693,7 +1699,7 @@ func TestInvalidHeaderField(t *testing.T) { } p := make([]byte, http2MaxFrameLen) _, err = s.trReader.(*transportReader).Read(p) - if se, ok := err.(StreamError); !ok || se.Code != codes.Internal || !strings.Contains(err.Error(), expectedInvalidHeaderField) { + if se, ok := status.FromError(err); !ok || se.Code() != codes.Internal || !strings.Contains(err.Error(), expectedInvalidHeaderField) { t.Fatalf("Read got error %v, want error with code %s and contains %q", err, codes.Internal, expectedInvalidHeaderField) } ct.Close() @@ -1730,25 +1736,18 @@ func TestContextErr(t *testing.T) { // input errIn error // outputs - errOut StreamError + errOut error }{ - {context.DeadlineExceeded, StreamError{codes.DeadlineExceeded, context.DeadlineExceeded.Error()}}, - {context.Canceled, StreamError{codes.Canceled, context.Canceled.Error()}}, + {context.DeadlineExceeded, status.Error(codes.DeadlineExceeded, context.DeadlineExceeded.Error())}, + {context.Canceled, status.Error(codes.Canceled, context.Canceled.Error())}, } { err := ContextErr(test.errIn) - if err != test.errOut { + if err.Error() != test.errOut.Error() { t.Fatalf("ContextErr{%v} = %v \nwant %v", test.errIn, err, test.errOut) } } } -func max(a, b int32) int32 { - if a > b { - return a - } - return b -} - type windowSizeConfig struct { serverStream int32 serverConn int32 @@ -1794,7 +1793,8 @@ func testFlowControlAccountCheck(t *testing.T, msgSize int, wc windowSizeConfig) InitialWindowSize: wc.clientStream, InitialConnWindowSize: wc.clientConn, } - server, client := setUpWithOptions(t, 0, sc, pingpong, co, func() {}) + server, client, cancel := setUpWithOptions(t, 0, sc, pingpong, co) + defer cancel() defer server.stop() defer client.Close() waitWhileTrue(t, func() (bool, error) { @@ -1811,69 +1811,96 @@ func testFlowControlAccountCheck(t *testing.T, msgSize int, wc windowSizeConfig) st = k.(*http2Server) } server.mu.Unlock() - ct := client.(*http2Client) - cstream, err := client.NewStream(context.Background(), &CallHdr{}) - if err != nil { - t.Fatalf("Failed to create stream. Err: %v", err) - } - msg := make([]byte, msgSize) - buf := make([]byte, msgSize+5) - buf[0] = byte(0) - binary.BigEndian.PutUint32(buf[1:], uint32(msgSize)) - copy(buf[5:], msg) - opts := Options{} - header := make([]byte, 5) - for i := 1; i <= 10; i++ { - if err := ct.Write(cstream, nil, buf, &opts); err != nil { - t.Fatalf("Error on client while writing message: %v", err) - } - if _, err := cstream.Read(header); err != nil { - t.Fatalf("Error on client while reading data frame header: %v", err) - } - sz := binary.BigEndian.Uint32(header[1:]) - recvMsg := make([]byte, int(sz)) - if _, err := cstream.Read(recvMsg); err != nil { - t.Fatalf("Error on client while reading data: %v", err) - } - if len(recvMsg) != len(msg) { - t.Fatalf("Length of message received by client: %v, want: %v", len(recvMsg), len(msg)) + const numStreams = 10 + clientStreams := make([]*Stream, numStreams) + for i := 0; i < numStreams; i++ { + var err error + clientStreams[i], err = client.NewStream(context.Background(), &CallHdr{}) + if err != nil { + t.Fatalf("Failed to create stream. Err: %v", err) } } - var sstream *Stream + var wg sync.WaitGroup + // For each stream send pingpong messages to the server. + for _, stream := range clientStreams { + wg.Add(1) + go func(stream *Stream) { + defer wg.Done() + buf := make([]byte, msgSize+5) + buf[0] = byte(0) + binary.BigEndian.PutUint32(buf[1:], uint32(msgSize)) + opts := Options{} + header := make([]byte, 5) + for i := 1; i <= 10; i++ { + if err := client.Write(stream, nil, buf, &opts); err != nil { + t.Errorf("Error on client while writing message: %v", err) + return + } + if _, err := stream.Read(header); err != nil { + t.Errorf("Error on client while reading data frame header: %v", err) + return + } + sz := binary.BigEndian.Uint32(header[1:]) + recvMsg := make([]byte, int(sz)) + if _, err := stream.Read(recvMsg); err != nil { + t.Errorf("Error on client while reading data: %v", err) + return + } + if len(recvMsg) != msgSize { + t.Errorf("Length of message received by client: %v, want: %v", len(recvMsg), msgSize) + return + } + } + }(stream) + } + wg.Wait() + serverStreams := map[uint32]*Stream{} + loopyClientStreams := map[uint32]*outStream{} + loopyServerStreams := map[uint32]*outStream{} + // Get all the streams from server reader and writer and client writer. st.mu.Lock() - for _, v := range st.activeStreams { - sstream = v + for _, stream := range clientStreams { + id := stream.id + serverStreams[id] = st.activeStreams[id] + loopyServerStreams[id] = st.loopy.estdStreams[id] + loopyClientStreams[id] = client.loopy.estdStreams[id] + } st.mu.Unlock() - loopyServerStream := st.loopy.estdStreams[sstream.id] - loopyClientStream := ct.loopy.estdStreams[cstream.id] - ct.Write(cstream, nil, nil, &Options{Last: true}) // Close the stream. - if _, err := cstream.Read(header); err != io.EOF { - t.Fatalf("Client expected an EOF from the server. Got: %v", err) - } - // Sleep for a little to make sure both sides flush out their buffers. - time.Sleep(time.Millisecond * 500) + // Close all streams + for _, stream := range clientStreams { + client.Write(stream, nil, nil, &Options{Last: true}) + if _, err := stream.Read(make([]byte, 5)); err != io.EOF { + t.Fatalf("Client expected an EOF from the server. Got: %v", err) + } + } // Close down both server and client so that their internals can be read without data // races. - ct.Close() + client.Close() st.Close() <-st.readerDone <-st.writerDone - <-ct.readerDone - <-ct.writerDone - // Check transport flow control. - if ct.fc.limit != ct.fc.unacked+st.loopy.sendQuota { - t.Fatalf("Account mismatch: client transport inflow(%d) != client unacked(%d) + server sendQuota(%d)", ct.fc.limit, ct.fc.unacked, st.loopy.sendQuota) - } - if st.fc.limit != st.fc.unacked+ct.loopy.sendQuota { - t.Fatalf("Account mismatch: server transport inflow(%d) != server unacked(%d) + client sendQuota(%d)", st.fc.limit, st.fc.unacked, ct.loopy.sendQuota) + <-client.readerDone + <-client.writerDone + for _, cstream := range clientStreams { + id := cstream.id + sstream := serverStreams[id] + loopyServerStream := loopyServerStreams[id] + loopyClientStream := loopyClientStreams[id] + // Check stream flow control. + if int(cstream.fc.limit+cstream.fc.delta-cstream.fc.pendingData-cstream.fc.pendingUpdate) != int(st.loopy.oiws)-loopyServerStream.bytesOutStanding { + t.Fatalf("Account mismatch: client stream inflow limit(%d) + delta(%d) - pendingData(%d) - pendingUpdate(%d) != server outgoing InitialWindowSize(%d) - outgoingStream.bytesOutStanding(%d)", cstream.fc.limit, cstream.fc.delta, cstream.fc.pendingData, cstream.fc.pendingUpdate, st.loopy.oiws, loopyServerStream.bytesOutStanding) + } + if int(sstream.fc.limit+sstream.fc.delta-sstream.fc.pendingData-sstream.fc.pendingUpdate) != int(client.loopy.oiws)-loopyClientStream.bytesOutStanding { + t.Fatalf("Account mismatch: server stream inflow limit(%d) + delta(%d) - pendingData(%d) - pendingUpdate(%d) != client outgoing InitialWindowSize(%d) - outgoingStream.bytesOutStanding(%d)", sstream.fc.limit, sstream.fc.delta, sstream.fc.pendingData, sstream.fc.pendingUpdate, client.loopy.oiws, loopyClientStream.bytesOutStanding) + } } - // Check stream flow control. - if int(cstream.fc.limit+cstream.fc.delta-cstream.fc.pendingData-cstream.fc.pendingUpdate) != int(st.loopy.oiws)-loopyServerStream.bytesOutStanding { - t.Fatalf("Account mismatch: client stream inflow limit(%d) + delta(%d) - pendingData(%d) - pendingUpdate(%d) != server outgoing InitialWindowSize(%d) - outgoingStream.bytesOutStanding(%d)", cstream.fc.limit, cstream.fc.delta, cstream.fc.pendingData, cstream.fc.pendingUpdate, st.loopy.oiws, loopyServerStream.bytesOutStanding) + // Check transport flow control. + if client.fc.limit != client.fc.unacked+st.loopy.sendQuota { + t.Fatalf("Account mismatch: client transport inflow(%d) != client unacked(%d) + server sendQuota(%d)", client.fc.limit, client.fc.unacked, st.loopy.sendQuota) } - if int(sstream.fc.limit+sstream.fc.delta-sstream.fc.pendingData-sstream.fc.pendingUpdate) != int(ct.loopy.oiws)-loopyClientStream.bytesOutStanding { - t.Fatalf("Account mismatch: server stream inflow limit(%d) + delta(%d) - pendingData(%d) - pendingUpdate(%d) != client outgoing InitialWindowSize(%d) - outgoingStream.bytesOutStanding(%d)", sstream.fc.limit, sstream.fc.delta, sstream.fc.pendingData, sstream.fc.pendingUpdate, ct.loopy.oiws, loopyClientStream.bytesOutStanding) + if st.fc.limit != st.fc.unacked+client.loopy.sendQuota { + t.Fatalf("Account mismatch: server transport inflow(%d) != server unacked(%d) + client sendQuota(%d)", st.fc.limit, st.fc.unacked, client.loopy.sendQuota) } } @@ -1945,7 +1972,6 @@ func writeTwoHeaders(framer *http2.Framer, sid uint32, httpStatus int) error { } type httpServer struct { - conn net.Conn httpStatus int wh writeHeaders } @@ -1953,19 +1979,19 @@ type httpServer struct { func (s *httpServer) start(t *testing.T, lis net.Listener) { // Launch an HTTP server to send back header with httpStatus. go func() { - var err error - s.conn, err = lis.Accept() + conn, err := lis.Accept() if err != nil { t.Errorf("Error accepting connection: %v", err) return } + defer conn.Close() // Read preface sent by client. - if _, err = io.ReadFull(s.conn, make([]byte, len(http2.ClientPreface))); err != nil { + if _, err = io.ReadFull(conn, make([]byte, len(http2.ClientPreface))); err != nil { t.Errorf("Error at server-side while reading preface from client. Err: %v", err) return } - reader := bufio.NewReaderSize(s.conn, defaultWriteBufSize) - writer := bufio.NewWriterSize(s.conn, defaultReadBufSize) + reader := bufio.NewReaderSize(conn, defaultWriteBufSize) + writer := bufio.NewWriterSize(conn, defaultReadBufSize) framer := http2.NewFramer(writer, reader) if err = framer.WriteSettingsAck(); err != nil { t.Errorf("Error at server-side while sending Settings ack. Err: %v", err) @@ -1992,55 +2018,33 @@ func (s *httpServer) start(t *testing.T, lis net.Listener) { }() } -func (s *httpServer) cleanUp() { - if s.conn != nil { - s.conn.Close() - } -} - -func setUpHTTPStatusTest(t *testing.T, httpStatus int, wh writeHeaders) (stream *Stream, cleanUp func()) { - var ( - err error - lis net.Listener - server *httpServer - client ClientTransport - ) - cleanUp = func() { - if lis != nil { - lis.Close() - } - if server != nil { - server.cleanUp() - } - if client != nil { - client.Close() - } - } - defer func() { - if err != nil { - cleanUp() - } - }() - lis, err = net.Listen("tcp", "localhost:0") +func setUpHTTPStatusTest(t *testing.T, httpStatus int, wh writeHeaders) (*Stream, func()) { + lis, err := net.Listen("tcp", "localhost:0") if err != nil { t.Fatalf("Failed to listen. Err: %v", err) } - server = &httpServer{ + server := &httpServer{ httpStatus: httpStatus, wh: wh, } server.start(t, lis) connectCtx, cancel := context.WithDeadline(context.Background(), time.Now().Add(2*time.Second)) - client, err = newHTTP2Client(connectCtx, context.Background(), TargetInfo{Addr: lis.Addr().String()}, ConnectOptions{}, func() {}) + defer cancel() + client, err := newHTTP2Client(connectCtx, context.Background(), TargetInfo{Addr: lis.Addr().String()}, ConnectOptions{}, func() {}, func(GoAwayReason) {}, func() {}) if err != nil { - cancel() // Do not cancel in success path. + lis.Close() t.Fatalf("Error creating client. Err: %v", err) } - stream, err = client.NewStream(context.Background(), &CallHdr{Method: "bogus/method", Flush: true}) + stream, err := client.NewStream(context.Background(), &CallHdr{Method: "bogus/method"}) if err != nil { + client.Close() + lis.Close() t.Fatalf("Error creating stream at client-side. Err: %v", err) } - return + return stream, func() { + client.Close() + lis.Close() + } } func TestHTTPToGRPCStatusMapping(t *testing.T) { @@ -2058,12 +2062,12 @@ func testHTTPToGRPCStatusMapping(t *testing.T, httpStatus int, wh writeHeaders) if err == nil { t.Fatalf("Stream.Read(_) unexpectedly returned no error. Expected stream error with code %v", want) } - serr, ok := err.(StreamError) + serr, ok := status.FromError(err) if !ok { - t.Fatalf("err.(Type) = %T, want StreamError", err) + t.Fatalf("err.(Type) = %T, want status error", err) } - if want != serr.Code { - t.Fatalf("Want error code: %v, got: %v", want, serr.Code) + if want != serr.Code() { + t.Fatalf("Want error code: %v, got: %v", want, serr.Code()) } } @@ -2149,7 +2153,8 @@ func TestPingPong1MB(t *testing.T) { //This is a stress-test of flow control logic. func runPingPongTest(t *testing.T, msgSize int) { - server, client := setUp(t, 0, 0, pingpong) + server, client, cancel := setUp(t, 0, 0, pingpong) + defer cancel() defer server.stop() defer client.Close() waitWhileTrue(t, func() (bool, error) { @@ -2160,7 +2165,6 @@ func runPingPongTest(t *testing.T, msgSize int) { } return false, nil }) - ct := client.(*http2Client) stream, err := client.NewStream(context.Background(), &CallHdr{}) if err != nil { t.Fatalf("Failed to create stream. Err: %v", err) @@ -2180,13 +2184,13 @@ func runPingPongTest(t *testing.T, msgSize int) { for { select { case <-done: - ct.Write(stream, nil, nil, &Options{Last: true}) + client.Write(stream, nil, nil, &Options{Last: true}) if _, err := stream.Read(incomingHeader); err != io.EOF { t.Fatalf("Client expected EOF from the server. Got: %v", err) } return default: - if err := ct.Write(stream, outgoingHeader, msg, opts); err != nil { + if err := client.Write(stream, outgoingHeader, msg, opts); err != nil { t.Fatalf("Error on client while writing message. Err: %v", err) } if _, err := stream.Read(incomingHeader); err != nil { @@ -2236,7 +2240,8 @@ func TestHeaderTblSize(t *testing.T) { } }() - server, ct := setUp(t, 0, math.MaxUint32, normal) + server, ct, cancel := setUp(t, 0, math.MaxUint32, normal) + defer cancel() defer ct.Close() defer server.stop() _, err := ct.NewStream(context.Background(), &CallHdr{}) @@ -2287,7 +2292,7 @@ func TestHeaderTblSize(t *testing.T) { t.Fatalf("expected len(limits) = 1 within 10s, got != 1") } - ct.(*http2Client).controlBuf.put(&outgoingSettings{ + ct.controlBuf.put(&outgoingSettings{ ss: []http2.Setting{ { ID: http2.SettingHeaderTableSize, @@ -2310,3 +2315,61 @@ func TestHeaderTblSize(t *testing.T) { t.Fatalf("expected len(limits) = 2 within 10s, got != 2") } } + +// TestTCPUserTimeout tests that the TCP_USER_TIMEOUT socket option is set to the +// keepalive timeout, as detailed in proposal A18 +func TestTCPUserTimeout(t *testing.T) { + tests := []struct { + time time.Duration + timeout time.Duration + }{ + { + 10 * time.Second, + 10 * time.Second, + }, + { + 0, + 0, + }, + } + for _, tt := range tests { + server, client, cancel := setUpWithOptions( + t, + 0, + &ServerConfig{ + KeepaliveParams: keepalive.ServerParameters{ + Time: tt.timeout, + Timeout: tt.timeout, + }, + }, + normal, + ConnectOptions{ + KeepaliveParams: keepalive.ClientParameters{ + Time: tt.time, + Timeout: tt.timeout, + }, + }, + ) + defer cancel() + defer server.stop() + defer client.Close() + + stream, err := client.NewStream(context.Background(), &CallHdr{}) + if err != nil { + t.Fatalf("Client failed to create RPC request: %v", err) + } + client.closeStream(stream, io.EOF, true, http2.ErrCodeCancel, nil, nil, false) + + opt, err := syscall.GetTCPUserTimeout(client.conn) + if err != nil { + t.Fatalf("GetTCPUserTimeout error: %v", err) + } + if opt < 0 { + t.Skipf("skipping test on unsupported environment") + } + if timeoutMS := int(tt.timeout / time.Millisecond); timeoutMS != opt { + t.Fatalf("wrong TCP_USER_TIMEOUT set on conn. expected %d. got %d", + timeoutMS, opt) + } + } +} diff --git a/vendor/google.golang.org/grpc/interop/alts/client/client.go b/vendor/google.golang.org/grpc/interop/alts/client/client.go index 3710c4b302143a653871ae0ed5492de5ea4c08f5..f3b1028bfbf6e73531ee217d60a308413cc66852 100644 --- a/vendor/google.golang.org/grpc/interop/alts/client/client.go +++ b/vendor/google.golang.org/grpc/interop/alts/client/client.go @@ -20,20 +20,16 @@ package main import ( + "context" "flag" "time" - "golang.org/x/net/context" grpc "google.golang.org/grpc" "google.golang.org/grpc/credentials/alts" "google.golang.org/grpc/grpclog" testpb "google.golang.org/grpc/interop/grpc_testing" ) -const ( - value = "test_value" -) - var ( hsAddr = flag.String("alts_handshaker_service_address", "", "ALTS handshaker gRPC service address") serverAddr = flag.String("server_address", ":8080", "The port on which the server is listening") diff --git a/vendor/google.golang.org/grpc/interop/client/client.go b/vendor/google.golang.org/grpc/interop/client/client.go index c8acae94b29543343315ea32ba9d1c97d1d383ef..1fa92f9abb7e3771cc503031fc8e84b8a9b6cd86 100644 --- a/vendor/google.golang.org/grpc/interop/client/client.go +++ b/vendor/google.golang.org/grpc/interop/client/client.go @@ -27,17 +27,24 @@ import ( _ "google.golang.org/grpc/balancer/grpclb" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/alts" + "google.golang.org/grpc/credentials/google" "google.golang.org/grpc/credentials/oauth" "google.golang.org/grpc/grpclog" "google.golang.org/grpc/interop" testpb "google.golang.org/grpc/interop/grpc_testing" + "google.golang.org/grpc/resolver" "google.golang.org/grpc/testdata" ) +const ( + googleDefaultCredsName = "google_default_credentials" +) + var ( caFile = flag.String("ca_file", "", "The file containning the CA root cert file") useTLS = flag.Bool("use_tls", false, "Connection uses TLS if true") useALTS = flag.Bool("use_alts", false, "Connection uses ALTS if true (this option can only be used on GCP)") + customCredentialsType = flag.String("custom_credentials_type", "", "Custom creds to use, excluding TLS or ALTS") altsHSAddr = flag.String("alts_handshaker_service_address", "", "ALTS handshaker gRPC service address") testCA = flag.Bool("use_test_ca", false, "Whether to replace platform root CAs with test CA as the CA root") serviceAccountKeyFile = flag.String("service_account_key_file", "", "Path to service account json key file") @@ -63,19 +70,49 @@ var ( cancel_after_begin: cancellation after metadata has been sent but before payloads are sent; cancel_after_first_response: cancellation after receiving 1st message from the server; status_code_and_message: status code propagated back to client; + special_status_message: Unicode and whitespace is correctly processed in status message; custom_metadata: server will echo custom metadata; unimplemented_method: client attempts to call unimplemented method; unimplemented_service: client attempts to call unimplemented service.`) ) +type credsMode uint8 + +const ( + credsNone credsMode = iota + credsTLS + credsALTS + credsGoogleDefaultCreds +) + func main() { flag.Parse() - if *useTLS && *useALTS { - grpclog.Fatalf("use_tls and use_alts cannot be both set to true") + var useGDC bool // use google default creds + if *customCredentialsType != "" { + if *customCredentialsType != googleDefaultCredsName { + grpclog.Fatalf("custom_credentials_type can only be set to %v or not set", googleDefaultCredsName) + } + useGDC = true + } + if (*useTLS && *useALTS) || (*useTLS && useGDC) || (*useALTS && useGDC) { + grpclog.Fatalf("only one of TLS, ALTS and google default creds can be used") } + + var credsChosen credsMode + switch { + case *useTLS: + credsChosen = credsTLS + case *useALTS: + credsChosen = credsALTS + case useGDC: + credsChosen = credsGoogleDefaultCreds + } + + resolver.SetDefaultScheme("dns") serverAddr := net.JoinHostPort(*serverHost, strconv.Itoa(*serverPort)) var opts []grpc.DialOption - if *useTLS { + switch credsChosen { + case credsTLS: var sn string if *tlsServerName != "" { sn = *tlsServerName @@ -94,6 +131,19 @@ func main() { creds = credentials.NewClientTLSFromCert(nil, sn) } opts = append(opts, grpc.WithTransportCredentials(creds)) + case credsALTS: + altsOpts := alts.DefaultClientOptions() + if *altsHSAddr != "" { + altsOpts.HandshakerServiceAddress = *altsHSAddr + } + altsTC := alts.NewClientCreds(altsOpts) + opts = append(opts, grpc.WithTransportCredentials(altsTC)) + case credsGoogleDefaultCreds: + opts = append(opts, grpc.WithCredentialsBundle(google.NewDefaultCredentials())) + default: + opts = append(opts, grpc.WithInsecure()) + } + if credsChosen == credsTLS || credsChosen == credsALTS { if *testCase == "compute_engine_creds" { opts = append(opts, grpc.WithPerRPCCredentials(oauth.NewComputeEngine())) } else if *testCase == "service_account_creds" { @@ -111,15 +161,6 @@ func main() { } else if *testCase == "oauth2_auth_token" { opts = append(opts, grpc.WithPerRPCCredentials(oauth.NewOauthAccess(interop.GetToken(*serviceAccountKeyFile, *oauthScope)))) } - } else if *useALTS { - altsOpts := alts.DefaultClientOptions() - if *altsHSAddr != "" { - altsOpts.HandshakerServiceAddress = *altsHSAddr - } - altsTC := alts.NewClientCreds(altsOpts) - opts = append(opts, grpc.WithTransportCredentials(altsTC)) - } else { - opts = append(opts, grpc.WithInsecure()) } opts = append(opts, grpc.WithBlock()) conn, err := grpc.Dial(serverAddr, opts...) @@ -151,32 +192,32 @@ func main() { interop.DoTimeoutOnSleepingServer(tc) grpclog.Infoln("TimeoutOnSleepingServer done") case "compute_engine_creds": - if !*useTLS { - grpclog.Fatalf("TLS is not enabled. TLS is required to execute compute_engine_creds test case.") + if credsChosen == credsNone { + grpclog.Fatalf("Credentials (TLS, ALTS or google default creds) need to be set for compute_engine_creds test case.") } interop.DoComputeEngineCreds(tc, *defaultServiceAccount, *oauthScope) grpclog.Infoln("ComputeEngineCreds done") case "service_account_creds": - if !*useTLS { - grpclog.Fatalf("TLS is not enabled. TLS is required to execute service_account_creds test case.") + if credsChosen == credsNone { + grpclog.Fatalf("Credentials (TLS, ALTS or google default creds) need to be set for service_account_creds test case.") } interop.DoServiceAccountCreds(tc, *serviceAccountKeyFile, *oauthScope) grpclog.Infoln("ServiceAccountCreds done") case "jwt_token_creds": - if !*useTLS { - grpclog.Fatalf("TLS is not enabled. TLS is required to execute jwt_token_creds test case.") + if credsChosen == credsNone { + grpclog.Fatalf("Credentials (TLS, ALTS or google default creds) need to be set for jwt_token_creds test case.") } interop.DoJWTTokenCreds(tc, *serviceAccountKeyFile) grpclog.Infoln("JWTtokenCreds done") case "per_rpc_creds": - if !*useTLS { - grpclog.Fatalf("TLS is not enabled. TLS is required to execute per_rpc_creds test case.") + if credsChosen == credsNone { + grpclog.Fatalf("Credentials (TLS, ALTS or google default creds) need to be set for per_rpc_creds test case.") } interop.DoPerRPCCreds(tc, *serviceAccountKeyFile, *oauthScope) grpclog.Infoln("PerRPCCreds done") case "oauth2_auth_token": - if !*useTLS { - grpclog.Fatalf("TLS is not enabled. TLS is required to execute oauth2_auth_token test case.") + if credsChosen == credsNone { + grpclog.Fatalf("Credentials (TLS, ALTS or google default creds) need to be set for oauth2_auth_token test case.") } interop.DoOauth2TokenCreds(tc, *serviceAccountKeyFile, *oauthScope) grpclog.Infoln("Oauth2TokenCreds done") @@ -189,6 +230,9 @@ func main() { case "status_code_and_message": interop.DoStatusCodeAndMessage(tc) grpclog.Infoln("StatusCodeAndMessage done") + case "special_status_message": + interop.DoSpecialStatusMessage(tc) + grpclog.Infoln("SpecialStatusMessage done") case "custom_metadata": interop.DoCustomMetadata(tc) grpclog.Infoln("CustomMetadata done") diff --git a/vendor/google.golang.org/grpc/interop/fake_grpclb/fake_grpclb.go b/vendor/google.golang.org/grpc/interop/fake_grpclb/fake_grpclb.go new file mode 100644 index 0000000000000000000000000000000000000000..f6d55045ee22eea1988f7f7b962ff3f6bc24635e --- /dev/null +++ b/vendor/google.golang.org/grpc/interop/fake_grpclb/fake_grpclb.go @@ -0,0 +1,169 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// This file is for testing only. Runs a fake grpclb balancer server. +// The name of the service to load balance for and the addresses +// of that service are provided by command line flags. +package main + +import ( + "flag" + "net" + "strconv" + "strings" + "time" + + "google.golang.org/grpc" + lbpb "google.golang.org/grpc/balancer/grpclb/grpc_lb_v1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/alts" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" + "google.golang.org/grpc/testdata" +) + +var ( + port = flag.Int("port", 10000, "Port to listen on.") + backendAddrs = flag.String("backend_addrs", "", "Comma separated list of backend IP/port addresses.") + useALTS = flag.Bool("use_alts", false, "Listen on ALTS credentials.") + useTLS = flag.Bool("use_tls", false, "Listen on TLS credentials, using a test certificate.") + shortStream = flag.Bool("short_stream", false, "End the balancer stream immediately after sending the first server list.") + serviceName = flag.String("service_name", "UNSET", "Name of the service being load balanced for.") +) + +type loadBalancerServer struct { + serverListResponse *lbpb.LoadBalanceResponse +} + +func (l *loadBalancerServer) BalanceLoad(stream lbpb.LoadBalancer_BalanceLoadServer) error { + grpclog.Info("Begin handling new BalancerLoad request.") + var lbReq *lbpb.LoadBalanceRequest + var err error + if lbReq, err = stream.Recv(); err != nil { + grpclog.Errorf("Error receiving LoadBalanceRequest: %v", err) + return err + } + grpclog.Info("LoadBalancerRequest received.") + initialReq := lbReq.GetInitialRequest() + if initialReq == nil { + grpclog.Info("Expected first request to be an InitialRequest. Got: %v", lbReq) + return status.Error(codes.Unknown, "First request not an InitialRequest") + } + // gRPC clients targeting foo.bar.com:443 can sometimes include the ":443" suffix in + // their requested names; handle this case. TODO: make 443 configurable? + var cleanedName string + var requestedNamePortNumber string + if cleanedName, requestedNamePortNumber, err = net.SplitHostPort(initialReq.Name); err != nil { + cleanedName = initialReq.Name + } else { + if requestedNamePortNumber != "443" { + grpclog.Info("Bad requested service name port number: %v.", requestedNamePortNumber) + return status.Error(codes.Unknown, "Bad requested service name port number") + } + } + if cleanedName != *serviceName { + grpclog.Info("Expected requested service name: %v. Got: %v", *serviceName, initialReq.Name) + return status.Error(codes.NotFound, "Bad requested service name") + } + if err := stream.Send(&lbpb.LoadBalanceResponse{ + LoadBalanceResponseType: &lbpb.LoadBalanceResponse_InitialResponse{ + InitialResponse: &lbpb.InitialLoadBalanceResponse{}, + }, + }); err != nil { + grpclog.Errorf("Error sending initial LB response: %v", err) + return status.Error(codes.Unknown, "Error sending initial response") + } + grpclog.Info("Send LoadBalanceResponse: %v", l.serverListResponse) + if err := stream.Send(l.serverListResponse); err != nil { + grpclog.Errorf("Error sending LB response: %v", err) + return status.Error(codes.Unknown, "Error sending response") + } + if *shortStream { + return nil + } + for { + grpclog.Info("Send LoadBalanceResponse: %v", l.serverListResponse) + if err := stream.Send(l.serverListResponse); err != nil { + grpclog.Errorf("Error sending LB response: %v", err) + return status.Error(codes.Unknown, "Error sending response") + } + time.Sleep(10 * time.Second) + } +} + +func main() { + flag.Parse() + var opts []grpc.ServerOption + if *useTLS { + certFile := testdata.Path("server1.pem") + keyFile := testdata.Path("server1.key") + creds, err := credentials.NewServerTLSFromFile(certFile, keyFile) + if err != nil { + grpclog.Fatalf("Failed to generate credentials %v", err) + } + opts = append(opts, grpc.Creds(creds)) + } else if *useALTS { + altsOpts := alts.DefaultServerOptions() + altsTC := alts.NewServerCreds(altsOpts) + opts = append(opts, grpc.Creds(altsTC)) + } + var serverList []*lbpb.Server + if len(*backendAddrs) == 0 { + serverList = make([]*lbpb.Server, 0) + } else { + rawBackendAddrs := strings.Split(*backendAddrs, ",") + serverList = make([]*lbpb.Server, len(rawBackendAddrs)) + for i := range rawBackendAddrs { + rawIP, rawPort, err := net.SplitHostPort(rawBackendAddrs[i]) + if err != nil { + grpclog.Fatalf("Failed to parse --backend_addrs[%d]=%v, error: %v", i, rawBackendAddrs[i], err) + } + ip := net.ParseIP(rawIP) + if ip == nil { + grpclog.Fatalf("Failed to parse ip: %v", rawIP) + } + numericPort, err := strconv.Atoi(rawPort) + if err != nil { + grpclog.Fatalf("Failed to convert port %v to int", rawPort) + } + grpclog.Infof("Adding backend ip: %v, port: %d", ip.String(), numericPort) + serverList[i] = &lbpb.Server{ + IpAddress: ip, + Port: int32(numericPort), + } + } + } + serverListResponse := &lbpb.LoadBalanceResponse{ + LoadBalanceResponseType: &lbpb.LoadBalanceResponse_ServerList{ + ServerList: &lbpb.ServerList{ + Servers: serverList, + }, + }, + } + server := grpc.NewServer(opts...) + grpclog.Infof("Begin listening on %d.", *port) + lis, err := net.Listen("tcp", ":"+strconv.Itoa(*port)) + if err != nil { + grpclog.Fatalf("Failed to listen on port %v: %v", *port, err) + } + lbpb.RegisterLoadBalancerServer(server, &loadBalancerServer{ + serverListResponse: serverListResponse, + }) + server.Serve(lis) +} diff --git a/vendor/google.golang.org/grpc/interop/http2/negative_http2_client.go b/vendor/google.golang.org/grpc/interop/http2/negative_http2_client.go index 7658a6342dced78803e0b02ffa4dfd5a29946f6d..2d7da138f34ba9ac9a84a1d715f02c8693925779 100644 --- a/vendor/google.golang.org/grpc/interop/http2/negative_http2_client.go +++ b/vendor/google.golang.org/grpc/interop/http2/negative_http2_client.go @@ -24,13 +24,13 @@ package main import ( + "context" "flag" "net" "strconv" "sync" "time" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/grpclog" diff --git a/vendor/google.golang.org/grpc/interop/test_utils.go b/vendor/google.golang.org/grpc/interop/test_utils.go index cbc7756d0335de01183722a04fb74a7bc4d22367..7ce970cc1ae1d9080089d73eb322c2ef4b8233ce 100644 --- a/vendor/google.golang.org/grpc/interop/test_utils.go +++ b/vendor/google.golang.org/grpc/interop/test_utils.go @@ -21,6 +21,7 @@ package interop import ( + "context" "fmt" "io" "io/ioutil" @@ -28,7 +29,6 @@ import ( "time" "github.com/golang/protobuf/proto" - "golang.org/x/net/context" "golang.org/x/oauth2" "golang.org/x/oauth2/google" "google.golang.org/grpc" @@ -563,6 +563,27 @@ func DoStatusCodeAndMessage(tc testpb.TestServiceClient, args ...grpc.CallOption } } +// DoSpecialStatusMessage verifies Unicode and whitespace is correctly processed +// in status message. +func DoSpecialStatusMessage(tc testpb.TestServiceClient, args ...grpc.CallOption) { + const ( + code int32 = 2 + msg string = "\t\ntest with whitespace\r\nand Unicode BMP ☺ and non-BMP 😈\t\n" + ) + expectedErr := status.Error(codes.Code(code), msg) + req := &testpb.SimpleRequest{ + ResponseStatus: &testpb.EchoStatus{ + Code: code, + Message: msg, + }, + } + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + if _, err := tc.UnaryCall(ctx, req, args...); err == nil || err.Error() != expectedErr.Error() { + grpclog.Fatalf("%v.UnaryCall(_, %v) = _, %v, want _, %v", tc, req, err, expectedErr) + } +} + // DoUnimplementedService attempts to call a method from an unimplemented service. func DoUnimplementedService(tc testpb.UnimplementedServiceClient) { _, err := tc.UnimplementedCall(context.Background(), &testpb.Empty{}) diff --git a/vendor/google.golang.org/grpc/keepalive/keepalive.go b/vendor/google.golang.org/grpc/keepalive/keepalive.go index f8adc7e6d4fa1db2a68ea956dd4eccc73c63a8a7..78eea1fc93bedbc0da9966d58dacbe5490b57c96 100644 --- a/vendor/google.golang.org/grpc/keepalive/keepalive.go +++ b/vendor/google.golang.org/grpc/keepalive/keepalive.go @@ -16,7 +16,8 @@ * */ -// Package keepalive defines configurable parameters for point-to-point healthcheck. +// Package keepalive defines configurable parameters for point-to-point +// healthcheck. package keepalive import ( @@ -24,42 +25,59 @@ import ( ) // ClientParameters is used to set keepalive parameters on the client-side. -// These configure how the client will actively probe to notice when a connection is broken -// and send pings so intermediaries will be aware of the liveness of the connection. -// Make sure these parameters are set in coordination with the keepalive policy on the server, -// as incompatible settings can result in closing of connection. +// These configure how the client will actively probe to notice when a +// connection is broken and send pings so intermediaries will be aware of the +// liveness of the connection. Make sure these parameters are set in +// coordination with the keepalive policy on the server, as incompatible +// settings can result in closing of connection. type ClientParameters struct { - // After a duration of this time if the client doesn't see any activity it pings the server to see if the transport is still alive. + // After a duration of this time if the client doesn't see any activity it + // pings the server to see if the transport is still alive. Time time.Duration // The current default value is infinity. - // After having pinged for keepalive check, the client waits for a duration of Timeout and if no activity is seen even after that - // the connection is closed. + // After having pinged for keepalive check, the client waits for a duration + // of Timeout and if no activity is seen even after that the connection is + // closed. Timeout time.Duration // The current default value is 20 seconds. - // If true, client runs keepalive checks even with no active RPCs. + // If true, client sends keepalive pings even with no active RPCs. If false, + // when there are no active RPCs, Time and Timeout will be ignored and no + // keepalive pings will be sent. PermitWithoutStream bool // false by default. } -// ServerParameters is used to set keepalive and max-age parameters on the server-side. +// ServerParameters is used to set keepalive and max-age parameters on the +// server-side. type ServerParameters struct { - // MaxConnectionIdle is a duration for the amount of time after which an idle connection would be closed by sending a GoAway. - // Idleness duration is defined since the most recent time the number of outstanding RPCs became zero or the connection establishment. + // MaxConnectionIdle is a duration for the amount of time after which an + // idle connection would be closed by sending a GoAway. Idleness duration is + // defined since the most recent time the number of outstanding RPCs became + // zero or the connection establishment. MaxConnectionIdle time.Duration // The current default value is infinity. - // MaxConnectionAge is a duration for the maximum amount of time a connection may exist before it will be closed by sending a GoAway. - // A random jitter of +/-10% will be added to MaxConnectionAge to spread out connection storms. + // MaxConnectionAge is a duration for the maximum amount of time a + // connection may exist before it will be closed by sending a GoAway. A + // random jitter of +/-10% will be added to MaxConnectionAge to spread out + // connection storms. MaxConnectionAge time.Duration // The current default value is infinity. - // MaxConnectinoAgeGrace is an additive period after MaxConnectionAge after which the connection will be forcibly closed. + // MaxConnectinoAgeGrace is an additive period after MaxConnectionAge after + // which the connection will be forcibly closed. MaxConnectionAgeGrace time.Duration // The current default value is infinity. - // After a duration of this time if the server doesn't see any activity it pings the client to see if the transport is still alive. + // After a duration of this time if the server doesn't see any activity it + // pings the client to see if the transport is still alive. Time time.Duration // The current default value is 2 hours. - // After having pinged for keepalive check, the server waits for a duration of Timeout and if no activity is seen even after that - // the connection is closed. + // After having pinged for keepalive check, the server waits for a duration + // of Timeout and if no activity is seen even after that the connection is + // closed. Timeout time.Duration // The current default value is 20 seconds. } -// EnforcementPolicy is used to set keepalive enforcement policy on the server-side. -// Server will close connection with a client that violates this policy. +// EnforcementPolicy is used to set keepalive enforcement policy on the +// server-side. Server will close connection with a client that violates this +// policy. type EnforcementPolicy struct { - // MinTime is the minimum amount of time a client should wait before sending a keepalive ping. + // MinTime is the minimum amount of time a client should wait before sending + // a keepalive ping. MinTime time.Duration // The current default value is 5 minutes. - // If true, server expects keepalive pings even when there are no active streams(RPCs). + // If true, server allows keepalive pings even when there are no active + // streams(RPCs). If false, and client sends ping when there are no active + // streams, server will send GOAWAY and close the connection. PermitWithoutStream bool // false by default. } diff --git a/vendor/google.golang.org/grpc/metadata/metadata.go b/vendor/google.golang.org/grpc/metadata/metadata.go index bd2eaf408376cb6a42c166db1ee9576c35ca9e45..cf6d1b94781ca3dba84f6c329337a91f83254e82 100644 --- a/vendor/google.golang.org/grpc/metadata/metadata.go +++ b/vendor/google.golang.org/grpc/metadata/metadata.go @@ -22,10 +22,9 @@ package metadata // import "google.golang.org/grpc/metadata" import ( + "context" "fmt" "strings" - - "golang.org/x/net/context" ) // DecodeKeyValue returns k, v, nil. diff --git a/vendor/google.golang.org/grpc/metadata/metadata_test.go b/vendor/google.golang.org/grpc/metadata/metadata_test.go index 4392145dee0ec6989eccd9da864cec8fe2a73d5c..f166ffaf76bc3439d0925ab6537788720dc82c1c 100644 --- a/vendor/google.golang.org/grpc/metadata/metadata_test.go +++ b/vendor/google.golang.org/grpc/metadata/metadata_test.go @@ -19,11 +19,10 @@ package metadata import ( + "context" "reflect" "strconv" "testing" - - "golang.org/x/net/context" ) func TestPairsMD(t *testing.T) { @@ -46,12 +45,12 @@ func TestPairsMD(t *testing.T) { func TestCopy(t *testing.T) { const key, val = "key", "val" orig := Pairs(key, val) - copy := orig.Copy() - if !reflect.DeepEqual(orig, copy) { - t.Errorf("copied value not equal to the original, got %v, want %v", copy, orig) + cpy := orig.Copy() + if !reflect.DeepEqual(orig, cpy) { + t.Errorf("copied value not equal to the original, got %v, want %v", cpy, orig) } orig[key][0] = "foo" - if v := copy[key][0]; v != val { + if v := cpy[key][0]; v != val { t.Errorf("change in original should not affect copy, got %q, want %q", v, val) } } diff --git a/vendor/google.golang.org/grpc/naming/dns_resolver.go b/vendor/google.golang.org/grpc/naming/dns_resolver.go index 0f8a908ea9c1ffdee7fc8b694005ff24a20d00b8..fd8cd3b5a4ff4bf1a997532ead95df1a2fa0f152 100644 --- a/vendor/google.golang.org/grpc/naming/dns_resolver.go +++ b/vendor/google.golang.org/grpc/naming/dns_resolver.go @@ -19,13 +19,13 @@ package naming import ( + "context" "errors" "fmt" "net" "strconv" "time" - "golang.org/x/net/context" "google.golang.org/grpc/grpclog" ) @@ -37,6 +37,9 @@ const ( var ( errMissingAddr = errors.New("missing address") errWatcherClose = errors.New("watcher has been closed") + + lookupHost = net.DefaultResolver.LookupHost + lookupSRV = net.DefaultResolver.LookupSRV ) // NewDNSResolverWithFreq creates a DNS Resolver that can resolve DNS names, and diff --git a/vendor/google.golang.org/grpc/naming/dns_resolver_test.go b/vendor/google.golang.org/grpc/naming/dns_resolver_test.go index be1ac1aeca717675af6d5eeb976fb678e0ef701f..42868a5d0bd4f021b0bea7817ad5faa0f0702dd7 100644 --- a/vendor/google.golang.org/grpc/naming/dns_resolver_test.go +++ b/vendor/google.golang.org/grpc/naming/dns_resolver_test.go @@ -19,6 +19,7 @@ package naming import ( + "context" "fmt" "net" "reflect" @@ -253,6 +254,21 @@ func testResolver(t *testing.T, freq time.Duration, slp time.Duration) { } } +func replaceNetFunc() func() { + oldLookupHost := lookupHost + oldLookupSRV := lookupSRV + lookupHost = func(ctx context.Context, host string) ([]string, error) { + return hostLookup(host) + } + lookupSRV = func(ctx context.Context, service, proto, name string) (string, []*net.SRV, error) { + return srvLookup(service, proto, name) + } + return func() { + lookupHost = oldLookupHost + lookupSRV = oldLookupSRV + } +} + func TestResolve(t *testing.T) { defer replaceNetFunc()() testResolver(t, time.Millisecond*5, time.Millisecond*10) diff --git a/vendor/google.golang.org/grpc/naming/go17_test.go b/vendor/google.golang.org/grpc/naming/go17_test.go deleted file mode 100644 index db39b9ab7841a04093706f402831df05a871ad9e..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/naming/go17_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// +build go1.6, !go1.8 - -/* - * - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package naming - -import ( - "net" - - "golang.org/x/net/context" -) - -func replaceNetFunc() func() { - oldLookupHost := lookupHost - oldLookupSRV := lookupSRV - lookupHost = func(ctx context.Context, host string) ([]string, error) { - return hostLookup(host) - } - lookupSRV = func(ctx context.Context, service, proto, name string) (string, []*net.SRV, error) { - return srvLookup(service, proto, name) - } - return func() { - lookupHost = oldLookupHost - lookupSRV = oldLookupSRV - } -} diff --git a/vendor/google.golang.org/grpc/naming/go18_test.go b/vendor/google.golang.org/grpc/naming/go18_test.go deleted file mode 100644 index 5e297539ba57f5ba7a782bdfa49cac5b3d72769e..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/naming/go18_test.go +++ /dev/null @@ -1,41 +0,0 @@ -// +build go1.8 - -/* - * - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package naming - -import ( - "context" - "net" -) - -func replaceNetFunc() func() { - oldLookupHost := lookupHost - oldLookupSRV := lookupSRV - lookupHost = func(ctx context.Context, host string) ([]string, error) { - return hostLookup(host) - } - lookupSRV = func(ctx context.Context, service, proto, name string) (string, []*net.SRV, error) { - return srvLookup(service, proto, name) - } - return func() { - lookupHost = oldLookupHost - lookupSRV = oldLookupSRV - } -} diff --git a/vendor/google.golang.org/grpc/peer/peer.go b/vendor/google.golang.org/grpc/peer/peer.go index 317b8b9d09a58a6da70d7fa44e7118e1fdc3cee3..e01d219ffbc58ed987190d15ee1b1ed0fce768bf 100644 --- a/vendor/google.golang.org/grpc/peer/peer.go +++ b/vendor/google.golang.org/grpc/peer/peer.go @@ -21,9 +21,9 @@ package peer import ( + "context" "net" - "golang.org/x/net/context" "google.golang.org/grpc/credentials" ) diff --git a/vendor/google.golang.org/grpc/picker_wrapper.go b/vendor/google.golang.org/grpc/picker_wrapper.go index 019e658004ebf34f8225670b81600fad5943c5d7..14f915d6768aa9338849bbedf281cccb88819621 100644 --- a/vendor/google.golang.org/grpc/picker_wrapper.go +++ b/vendor/google.golang.org/grpc/picker_wrapper.go @@ -19,19 +19,16 @@ package grpc import ( + "context" "io" "sync" - "sync/atomic" - "golang.org/x/net/context" "google.golang.org/grpc/balancer" "google.golang.org/grpc/codes" "google.golang.org/grpc/grpclog" "google.golang.org/grpc/internal/channelz" - "google.golang.org/grpc/metadata" - "google.golang.org/grpc/resolver" + "google.golang.org/grpc/internal/transport" "google.golang.org/grpc/status" - "google.golang.org/grpc/transport" ) // pickerWrapper is a wrapper of balancer.Picker. It blocks on certain pick @@ -45,16 +42,10 @@ type pickerWrapper struct { // The latest connection happened. connErrMu sync.Mutex connErr error - - stickinessMDKey atomic.Value - stickiness *stickyStore } func newPickerWrapper() *pickerWrapper { - bp := &pickerWrapper{ - blockingCh: make(chan struct{}), - stickiness: newStickyStore(), - } + bp := &pickerWrapper{blockingCh: make(chan struct{})} return bp } @@ -71,27 +62,6 @@ func (bp *pickerWrapper) connectionError() error { return err } -func (bp *pickerWrapper) updateStickinessMDKey(newKey string) { - // No need to check ok because mdKey == "" if ok == false. - if oldKey, _ := bp.stickinessMDKey.Load().(string); oldKey != newKey { - bp.stickinessMDKey.Store(newKey) - bp.stickiness.reset(newKey) - } -} - -func (bp *pickerWrapper) getStickinessMDKey() string { - // No need to check ok because mdKey == "" if ok == false. - mdKey, _ := bp.stickinessMDKey.Load().(string) - return mdKey -} - -func (bp *pickerWrapper) clearStickinessState() { - if oldKey := bp.getStickinessMDKey(); oldKey != "" { - // There's no need to reset store if mdKey was "". - bp.stickiness.reset(oldKey) - } -} - // updatePicker is called by UpdateBalancerState. It unblocks all blocked pick. func (bp *pickerWrapper) updatePicker(p balancer.Picker) { bp.mu.Lock() @@ -131,27 +101,6 @@ func doneChannelzWrapper(acw *acBalancerWrapper, done func(balancer.DoneInfo)) f // - the subConn returned by the current picker is not READY // When one of these situations happens, pick blocks until the picker gets updated. func (bp *pickerWrapper) pick(ctx context.Context, failfast bool, opts balancer.PickOptions) (transport.ClientTransport, func(balancer.DoneInfo), error) { - - mdKey := bp.getStickinessMDKey() - stickyKey, isSticky := stickyKeyFromContext(ctx, mdKey) - - // Potential race here: if stickinessMDKey is updated after the above two - // lines, and this pick is a sticky pick, the following put could add an - // entry to sticky store with an outdated sticky key. - // - // The solution: keep the current md key in sticky store, and at the - // beginning of each get/put, check the mdkey against store.curMDKey. - // - Cons: one more string comparing for each get/put. - // - Pros: the string matching happens inside get/put, so the overhead for - // non-sticky RPCs will be minimal. - - if isSticky { - if t, ok := bp.stickiness.get(mdKey, stickyKey); ok { - // Done function returned is always nil. - return t, nil, nil - } - } - var ( p balancer.Picker ch chan struct{} @@ -207,9 +156,6 @@ func (bp *pickerWrapper) pick(ctx context.Context, failfast bool, opts balancer. continue } if t, ok := acw.getAddrConn().getReadyTransport(); ok { - if isSticky { - bp.stickiness.put(mdKey, stickyKey, acw) - } if channelz.IsOn() { return t, doneChannelzWrapper(acw, done), nil } @@ -232,105 +178,3 @@ func (bp *pickerWrapper) close() { bp.done = true close(bp.blockingCh) } - -const stickinessKeyCountLimit = 1000 - -type stickyStoreEntry struct { - acw *acBalancerWrapper - addr resolver.Address -} - -type stickyStore struct { - mu sync.Mutex - // curMDKey is check before every get/put to avoid races. The operation will - // abort immediately when the given mdKey is different from the curMDKey. - curMDKey string - store *linkedMap -} - -func newStickyStore() *stickyStore { - return &stickyStore{ - store: newLinkedMap(), - } -} - -// reset clears the map in stickyStore, and set the currentMDKey to newMDKey. -func (ss *stickyStore) reset(newMDKey string) { - ss.mu.Lock() - ss.curMDKey = newMDKey - ss.store.clear() - ss.mu.Unlock() -} - -// stickyKey is the key to look up in store. mdKey will be checked against -// curMDKey to avoid races. -func (ss *stickyStore) put(mdKey, stickyKey string, acw *acBalancerWrapper) { - ss.mu.Lock() - defer ss.mu.Unlock() - if mdKey != ss.curMDKey { - return - } - // TODO(stickiness): limit the total number of entries. - ss.store.put(stickyKey, &stickyStoreEntry{ - acw: acw, - addr: acw.getAddrConn().getCurAddr(), - }) - if ss.store.len() > stickinessKeyCountLimit { - ss.store.removeOldest() - } -} - -// stickyKey is the key to look up in store. mdKey will be checked against -// curMDKey to avoid races. -func (ss *stickyStore) get(mdKey, stickyKey string) (transport.ClientTransport, bool) { - ss.mu.Lock() - defer ss.mu.Unlock() - if mdKey != ss.curMDKey { - return nil, false - } - entry, ok := ss.store.get(stickyKey) - if !ok { - return nil, false - } - ac := entry.acw.getAddrConn() - if ac.getCurAddr() != entry.addr { - ss.store.remove(stickyKey) - return nil, false - } - t, ok := ac.getReadyTransport() - if !ok { - ss.store.remove(stickyKey) - return nil, false - } - return t, true -} - -// Get one value from metadata in ctx with key stickinessMDKey. -// -// It returns "", false if stickinessMDKey is an empty string. -func stickyKeyFromContext(ctx context.Context, stickinessMDKey string) (string, bool) { - if stickinessMDKey == "" { - return "", false - } - - md, added, ok := metadata.FromOutgoingContextRaw(ctx) - if !ok { - return "", false - } - - if vv, ok := md[stickinessMDKey]; ok { - if len(vv) > 0 { - return vv[0], true - } - } - - for _, ss := range added { - for i := 0; i < len(ss)-1; i += 2 { - if ss[i] == stickinessMDKey { - return ss[i+1], true - } - } - } - - return "", false -} diff --git a/vendor/google.golang.org/grpc/picker_wrapper_test.go b/vendor/google.golang.org/grpc/picker_wrapper_test.go index d455286d34773e6d7d4b9900f8039aadbd0de010..36653b12e7e1bb5d4cd12d9286c4c685486e1614 100644 --- a/vendor/google.golang.org/grpc/picker_wrapper_test.go +++ b/vendor/google.golang.org/grpc/picker_wrapper_test.go @@ -19,17 +19,17 @@ package grpc import ( + "context" "fmt" "sync/atomic" "testing" "time" - "golang.org/x/net/context" "google.golang.org/grpc/balancer" "google.golang.org/grpc/connectivity" _ "google.golang.org/grpc/grpclog/glogger" "google.golang.org/grpc/internal/leakcheck" - "google.golang.org/grpc/transport" + "google.golang.org/grpc/internal/transport" ) const goroutineCount = 5 diff --git a/vendor/google.golang.org/grpc/pickfirst.go b/vendor/google.golang.org/grpc/pickfirst.go index bf659d49d2f17c36f797b28130e08ee0292e0972..d1e38aad778b44df4e452455d5b5f66d32aa729e 100644 --- a/vendor/google.golang.org/grpc/pickfirst.go +++ b/vendor/google.golang.org/grpc/pickfirst.go @@ -19,7 +19,8 @@ package grpc import ( - "golang.org/x/net/context" + "context" + "google.golang.org/grpc/balancer" "google.golang.org/grpc/connectivity" "google.golang.org/grpc/grpclog" @@ -56,6 +57,7 @@ func (b *pickfirstBalancer) HandleResolvedAddrs(addrs []resolver.Address, err er if b.sc == nil { b.sc, err = b.cc.NewSubConn(addrs, balancer.NewSubConnOptions{}) if err != nil { + //TODO(yuxuanli): why not change the cc state to Idle? grpclog.Errorf("pickfirstBalancer: failed to NewSubConn: %v", err) return } diff --git a/vendor/google.golang.org/grpc/pickfirst_test.go b/vendor/google.golang.org/grpc/pickfirst_test.go index 7f8169f19fe3d90b20030309a3fa4d5615906da1..675067fd9d41ad25a24ff5abcf4767c1ab1f3736 100644 --- a/vendor/google.golang.org/grpc/pickfirst_test.go +++ b/vendor/google.golang.org/grpc/pickfirst_test.go @@ -19,12 +19,12 @@ package grpc import ( + "context" "math" "sync" "testing" "time" - "golang.org/x/net/context" "google.golang.org/grpc/codes" "google.golang.org/grpc/internal/leakcheck" "google.golang.org/grpc/resolver" diff --git a/vendor/google.golang.org/grpc/proxy.go b/vendor/google.golang.org/grpc/proxy.go index 2d40236e21806fca6f14ceb875654f44c660dd4d..f8f69bfb70fd9309875cfb567597ef02c0ed2e3a 100644 --- a/vendor/google.golang.org/grpc/proxy.go +++ b/vendor/google.golang.org/grpc/proxy.go @@ -20,6 +20,8 @@ package grpc import ( "bufio" + "context" + "encoding/base64" "errors" "fmt" "io" @@ -27,10 +29,10 @@ import ( "net/http" "net/http/httputil" "net/url" - - "golang.org/x/net/context" ) +const proxyAuthHeaderKey = "Proxy-Authorization" + var ( // errDisabled indicates that proxy is disabled for the address. errDisabled = errors.New("proxy is disabled for the address") @@ -38,7 +40,7 @@ var ( httpProxyFromEnvironment = http.ProxyFromEnvironment ) -func mapAddress(ctx context.Context, address string) (string, error) { +func mapAddress(ctx context.Context, address string) (*url.URL, error) { req := &http.Request{ URL: &url.URL{ Scheme: "https", @@ -47,12 +49,12 @@ func mapAddress(ctx context.Context, address string) (string, error) { } url, err := httpProxyFromEnvironment(req) if err != nil { - return "", err + return nil, err } if url == nil { - return "", errDisabled + return nil, errDisabled } - return url.Host, nil + return url, nil } // To read a response from a net.Conn, http.ReadResponse() takes a bufio.Reader. @@ -69,18 +71,28 @@ func (c *bufConn) Read(b []byte) (int, error) { return c.r.Read(b) } -func doHTTPConnectHandshake(ctx context.Context, conn net.Conn, addr string) (_ net.Conn, err error) { +func basicAuth(username, password string) string { + auth := username + ":" + password + return base64.StdEncoding.EncodeToString([]byte(auth)) +} + +func doHTTPConnectHandshake(ctx context.Context, conn net.Conn, backendAddr string, proxyURL *url.URL) (_ net.Conn, err error) { defer func() { if err != nil { conn.Close() } }() - req := (&http.Request{ + req := &http.Request{ Method: http.MethodConnect, - URL: &url.URL{Host: addr}, + URL: &url.URL{Host: backendAddr}, Header: map[string][]string{"User-Agent": {grpcUA}}, - }) + } + if t := proxyURL.User; t != nil { + u := t.Username() + p, _ := t.Password() + req.Header.Add(proxyAuthHeaderKey, "Basic "+basicAuth(u, p)) + } if err := sendHTTPRequest(ctx, req, conn); err != nil { return nil, fmt.Errorf("failed to write the HTTP request: %v", err) @@ -108,23 +120,33 @@ func doHTTPConnectHandshake(ctx context.Context, conn net.Conn, addr string) (_ // provided dialer, does HTTP CONNECT handshake and returns the connection. func newProxyDialer(dialer func(context.Context, string) (net.Conn, error)) func(context.Context, string) (net.Conn, error) { return func(ctx context.Context, addr string) (conn net.Conn, err error) { - var skipHandshake bool - newAddr, err := mapAddress(ctx, addr) + var newAddr string + proxyURL, err := mapAddress(ctx, addr) if err != nil { if err != errDisabled { return nil, err } - skipHandshake = true newAddr = addr + } else { + newAddr = proxyURL.Host } conn, err = dialer(ctx, newAddr) if err != nil { return } - if !skipHandshake { - conn, err = doHTTPConnectHandshake(ctx, conn, addr) + if proxyURL != nil { + // proxy is disabled if proxyURL is nil. + conn, err = doHTTPConnectHandshake(ctx, conn, addr, proxyURL) } return } } + +func sendHTTPRequest(ctx context.Context, req *http.Request, conn net.Conn) error { + req = req.WithContext(ctx) + if err := req.Write(conn); err != nil { + return fmt.Errorf("failed to write the HTTP request: %v", err) + } + return nil +} diff --git a/vendor/google.golang.org/grpc/proxy_test.go b/vendor/google.golang.org/grpc/proxy_test.go index 7183ba3425540dc70b01bde3894bf415dd5aa1aa..9ab72cb8a0a908aa6212af9eaa10abe35aecf1e3 100644 --- a/vendor/google.golang.org/grpc/proxy_test.go +++ b/vendor/google.golang.org/grpc/proxy_test.go @@ -22,6 +22,9 @@ package grpc import ( "bufio" + "context" + "encoding/base64" + "fmt" "io" "net" "net/http" @@ -29,7 +32,6 @@ import ( "testing" "time" - "golang.org/x/net/context" "google.golang.org/grpc/internal/leakcheck" ) @@ -53,6 +55,8 @@ type proxyServer struct { lis net.Listener in net.Conn out net.Conn + + requestCheck func(*http.Request) error } func (p *proxyServer) run() { @@ -67,11 +71,11 @@ func (p *proxyServer) run() { p.t.Errorf("failed to read CONNECT req: %v", err) return } - if req.Method != http.MethodConnect || req.UserAgent() != grpcUA { + if err := p.requestCheck(req); err != nil { resp := http.Response{StatusCode: http.StatusMethodNotAllowed} resp.Write(p.in) p.in.Close() - p.t.Errorf("get wrong CONNECT req: %+v", req) + p.t.Errorf("get wrong CONNECT req: %+v, error: %v", req, err) return } @@ -97,13 +101,17 @@ func (p *proxyServer) stop() { } } -func TestHTTPConnect(t *testing.T) { +func testHTTPConnect(t *testing.T, proxyURLModify func(*url.URL) *url.URL, proxyReqCheck func(*http.Request) error) { defer leakcheck.Check(t) plis, err := net.Listen("tcp", "localhost:0") if err != nil { t.Fatalf("failed to listen: %v", err) } - p := &proxyServer{t: t, lis: plis} + p := &proxyServer{ + t: t, + lis: plis, + requestCheck: proxyReqCheck, + } go p.run() defer p.stop() @@ -128,7 +136,7 @@ func TestHTTPConnect(t *testing.T) { // Overwrite the function in the test and restore them in defer. hpfe := func(req *http.Request) (*url.URL, error) { - return &url.URL{Host: plis.Addr().String()}, nil + return proxyURLModify(&url.URL{Host: plis.Addr().String()}), nil } defer overwrite(hpfe)() @@ -157,6 +165,51 @@ func TestHTTPConnect(t *testing.T) { } } +func TestHTTPConnect(t *testing.T) { + testHTTPConnect(t, + func(in *url.URL) *url.URL { + return in + }, + func(req *http.Request) error { + if req.Method != http.MethodConnect { + return fmt.Errorf("unexpected Method %q, want %q", req.Method, http.MethodConnect) + } + if req.UserAgent() != grpcUA { + return fmt.Errorf("unexpect user agent %q, want %q", req.UserAgent(), grpcUA) + } + return nil + }, + ) +} + +func TestHTTPConnectBasicAuth(t *testing.T) { + const ( + user = "notAUser" + password = "notAPassword" + ) + testHTTPConnect(t, + func(in *url.URL) *url.URL { + in.User = url.UserPassword(user, password) + return in + }, + func(req *http.Request) error { + if req.Method != http.MethodConnect { + return fmt.Errorf("unexpected Method %q, want %q", req.Method, http.MethodConnect) + } + if req.UserAgent() != grpcUA { + return fmt.Errorf("unexpect user agent %q, want %q", req.UserAgent(), grpcUA) + } + wantProxyAuthStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(user+":"+password)) + if got := req.Header.Get(proxyAuthHeaderKey); got != wantProxyAuthStr { + gotDecoded, _ := base64.StdEncoding.DecodeString(got) + wantDecoded, _ := base64.StdEncoding.DecodeString(wantProxyAuthStr) + return fmt.Errorf("unexpected auth %q (%q), want %q (%q)", got, gotDecoded, wantProxyAuthStr, wantDecoded) + } + return nil + }, + ) +} + func TestMapAddressEnv(t *testing.T) { defer leakcheck.Check(t) // Overwrite the function in the test and restore them in defer. @@ -176,7 +229,7 @@ func TestMapAddressEnv(t *testing.T) { if err != nil { t.Error(err) } - if got != envProxyAddr { + if got.Host != envProxyAddr { t.Errorf("want %v, got %v", envProxyAddr, got) } } diff --git a/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection.pb.go b/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection.pb.go index 4bc5404ae3566ba1b109eddc5679206950f6dd4d..ae5aa7dbe57d1c30969de7cbef3f105119b6a637 100644 --- a/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection.pb.go +++ b/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection.pb.go @@ -66,6 +66,13 @@ func (m *ServerReflectionRequest) XXX_DiscardUnknown() { var xxx_messageInfo_ServerReflectionRequest proto.InternalMessageInfo +func (m *ServerReflectionRequest) GetHost() string { + if m != nil { + return m.Host + } + return "" +} + type isServerReflectionRequest_MessageRequest interface { isServerReflectionRequest_MessageRequest() } @@ -73,24 +80,32 @@ type isServerReflectionRequest_MessageRequest interface { type ServerReflectionRequest_FileByFilename struct { FileByFilename string `protobuf:"bytes,3,opt,name=file_by_filename,json=fileByFilename,proto3,oneof"` } + type ServerReflectionRequest_FileContainingSymbol struct { FileContainingSymbol string `protobuf:"bytes,4,opt,name=file_containing_symbol,json=fileContainingSymbol,proto3,oneof"` } + type ServerReflectionRequest_FileContainingExtension struct { FileContainingExtension *ExtensionRequest `protobuf:"bytes,5,opt,name=file_containing_extension,json=fileContainingExtension,proto3,oneof"` } + type ServerReflectionRequest_AllExtensionNumbersOfType struct { AllExtensionNumbersOfType string `protobuf:"bytes,6,opt,name=all_extension_numbers_of_type,json=allExtensionNumbersOfType,proto3,oneof"` } + type ServerReflectionRequest_ListServices struct { ListServices string `protobuf:"bytes,7,opt,name=list_services,json=listServices,proto3,oneof"` } -func (*ServerReflectionRequest_FileByFilename) isServerReflectionRequest_MessageRequest() {} -func (*ServerReflectionRequest_FileContainingSymbol) isServerReflectionRequest_MessageRequest() {} -func (*ServerReflectionRequest_FileContainingExtension) isServerReflectionRequest_MessageRequest() {} +func (*ServerReflectionRequest_FileByFilename) isServerReflectionRequest_MessageRequest() {} + +func (*ServerReflectionRequest_FileContainingSymbol) isServerReflectionRequest_MessageRequest() {} + +func (*ServerReflectionRequest_FileContainingExtension) isServerReflectionRequest_MessageRequest() {} + func (*ServerReflectionRequest_AllExtensionNumbersOfType) isServerReflectionRequest_MessageRequest() {} -func (*ServerReflectionRequest_ListServices) isServerReflectionRequest_MessageRequest() {} + +func (*ServerReflectionRequest_ListServices) isServerReflectionRequest_MessageRequest() {} func (m *ServerReflectionRequest) GetMessageRequest() isServerReflectionRequest_MessageRequest { if m != nil { @@ -99,13 +114,6 @@ func (m *ServerReflectionRequest) GetMessageRequest() isServerReflectionRequest_ return nil } -func (m *ServerReflectionRequest) GetHost() string { - if m != nil { - return m.Host - } - return "" -} - func (m *ServerReflectionRequest) GetFileByFilename() string { if x, ok := m.GetMessageRequest().(*ServerReflectionRequest_FileByFilename); ok { return x.FileByFilename @@ -347,6 +355,20 @@ func (m *ServerReflectionResponse) XXX_DiscardUnknown() { var xxx_messageInfo_ServerReflectionResponse proto.InternalMessageInfo +func (m *ServerReflectionResponse) GetValidHost() string { + if m != nil { + return m.ValidHost + } + return "" +} + +func (m *ServerReflectionResponse) GetOriginalRequest() *ServerReflectionRequest { + if m != nil { + return m.OriginalRequest + } + return nil +} + type isServerReflectionResponse_MessageResponse interface { isServerReflectionResponse_MessageResponse() } @@ -354,21 +376,27 @@ type isServerReflectionResponse_MessageResponse interface { type ServerReflectionResponse_FileDescriptorResponse struct { FileDescriptorResponse *FileDescriptorResponse `protobuf:"bytes,4,opt,name=file_descriptor_response,json=fileDescriptorResponse,proto3,oneof"` } + type ServerReflectionResponse_AllExtensionNumbersResponse struct { AllExtensionNumbersResponse *ExtensionNumberResponse `protobuf:"bytes,5,opt,name=all_extension_numbers_response,json=allExtensionNumbersResponse,proto3,oneof"` } + type ServerReflectionResponse_ListServicesResponse struct { ListServicesResponse *ListServiceResponse `protobuf:"bytes,6,opt,name=list_services_response,json=listServicesResponse,proto3,oneof"` } + type ServerReflectionResponse_ErrorResponse struct { ErrorResponse *ErrorResponse `protobuf:"bytes,7,opt,name=error_response,json=errorResponse,proto3,oneof"` } func (*ServerReflectionResponse_FileDescriptorResponse) isServerReflectionResponse_MessageResponse() {} + func (*ServerReflectionResponse_AllExtensionNumbersResponse) isServerReflectionResponse_MessageResponse() { } + func (*ServerReflectionResponse_ListServicesResponse) isServerReflectionResponse_MessageResponse() {} -func (*ServerReflectionResponse_ErrorResponse) isServerReflectionResponse_MessageResponse() {} + +func (*ServerReflectionResponse_ErrorResponse) isServerReflectionResponse_MessageResponse() {} func (m *ServerReflectionResponse) GetMessageResponse() isServerReflectionResponse_MessageResponse { if m != nil { @@ -377,20 +405,6 @@ func (m *ServerReflectionResponse) GetMessageResponse() isServerReflectionRespon return nil } -func (m *ServerReflectionResponse) GetValidHost() string { - if m != nil { - return m.ValidHost - } - return "" -} - -func (m *ServerReflectionResponse) GetOriginalRequest() *ServerReflectionRequest { - if m != nil { - return m.OriginalRequest - } - return nil -} - func (m *ServerReflectionResponse) GetFileDescriptorResponse() *FileDescriptorResponse { if x, ok := m.GetMessageResponse().(*ServerReflectionResponse_FileDescriptorResponse); ok { return x.FileDescriptorResponse diff --git a/vendor/google.golang.org/grpc/reflection/serverreflection_test.go b/vendor/google.golang.org/grpc/reflection/serverreflection_test.go index e2c7416970d8bc65e79920b001df6eb06be5d1fa..9078b2055ce7e88bb88958b1550f20278faef353 100644 --- a/vendor/google.golang.org/grpc/reflection/serverreflection_test.go +++ b/vendor/google.golang.org/grpc/reflection/serverreflection_test.go @@ -24,6 +24,7 @@ package reflection import ( + "context" "fmt" "net" "reflect" @@ -32,7 +33,6 @@ import ( "github.com/golang/protobuf/proto" dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" - "golang.org/x/net/context" "google.golang.org/grpc" rpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" pb "google.golang.org/grpc/reflection/grpc_testing" diff --git a/vendor/google.golang.org/grpc/resolver/dns/dns_resolver.go b/vendor/google.golang.org/grpc/resolver/dns/dns_resolver.go index 048fde67d00aba5e98d298b757d397404dd85fc2..f33189fede2d16813e938659507cf51c81111915 100644 --- a/vendor/google.golang.org/grpc/resolver/dns/dns_resolver.go +++ b/vendor/google.golang.org/grpc/resolver/dns/dns_resolver.go @@ -1,6 +1,6 @@ /* * - * Copyright 2017 gRPC authors. + * Copyright 2018 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ package dns import ( + "context" "encoding/json" "errors" "fmt" @@ -31,8 +32,8 @@ import ( "sync" "time" - "golang.org/x/net/context" "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/internal/backoff" "google.golang.org/grpc/internal/grpcrand" "google.golang.org/grpc/resolver" ) @@ -42,34 +43,63 @@ func init() { } const ( - defaultPort = "443" - defaultFreq = time.Minute * 30 - golang = "GO" + defaultPort = "443" + defaultFreq = time.Minute * 30 + defaultDNSSvrPort = "53" + golang = "GO" // In DNS, service config is encoded in a TXT record via the mechanism // described in RFC-1464 using the attribute name grpc_config. txtAttribute = "grpc_config=" ) var ( - errMissingAddr = errors.New("missing address") + errMissingAddr = errors.New("dns resolver: missing address") + + // Addresses ending with a colon that is supposed to be the separator + // between host and port is not allowed. E.g. "::" is a valid address as + // it is an IPv6 address (host only) and "[::]:" is invalid as it ends with + // a colon as the host and port separator + errEndsWithColon = errors.New("dns resolver: missing port after port-separator colon") +) + +var ( + defaultResolver netResolver = net.DefaultResolver ) +var customAuthorityDialler = func(authority string) func(ctx context.Context, network, address string) (net.Conn, error) { + return func(ctx context.Context, network, address string) (net.Conn, error) { + var dialer net.Dialer + return dialer.DialContext(ctx, network, authority) + } +} + +var customAuthorityResolver = func(authority string) (netResolver, error) { + host, port, err := parseTarget(authority, defaultDNSSvrPort) + if err != nil { + return nil, err + } + + authorityWithPort := net.JoinHostPort(host, port) + + return &net.Resolver{ + PreferGo: true, + Dial: customAuthorityDialler(authorityWithPort), + }, nil +} + // NewBuilder creates a dnsBuilder which is used to factory DNS resolvers. func NewBuilder() resolver.Builder { - return &dnsBuilder{freq: defaultFreq} + return &dnsBuilder{minFreq: defaultFreq} } type dnsBuilder struct { - // frequency of polling the DNS server. - freq time.Duration + // minimum frequency of polling the DNS server. + minFreq time.Duration } // Build creates and starts a DNS resolver that watches the name resolution of the target. func (b *dnsBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOption) (resolver.Resolver, error) { - if target.Authority != "" { - return nil, fmt.Errorf("Default DNS resolver does not support custom DNS server") - } - host, port, err := parseTarget(target.Endpoint) + host, port, err := parseTarget(target.Endpoint, defaultPort) if err != nil { return nil, err } @@ -92,7 +122,8 @@ func (b *dnsBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts // DNS address (non-IP). ctx, cancel := context.WithCancel(context.Background()) d := &dnsResolver{ - freq: b.freq, + freq: b.minFreq, + backoff: backoff.Exponential{MaxDelay: b.minFreq}, host: host, port: port, ctx: ctx, @@ -103,6 +134,15 @@ func (b *dnsBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts disableServiceConfig: opts.DisableServiceConfig, } + if target.Authority == "" { + d.resolver = defaultResolver + } else { + d.resolver, err = customAuthorityResolver(target.Authority) + if err != nil { + return nil, err + } + } + d.wg.Add(1) go d.watcher() return d, nil @@ -113,6 +153,12 @@ func (b *dnsBuilder) Scheme() string { return "dns" } +type netResolver interface { + LookupHost(ctx context.Context, host string) (addrs []string, err error) + LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*net.SRV, err error) + LookupTXT(ctx context.Context, name string) (txts []string, err error) +} + // ipResolver watches for the name resolution update for an IP address. type ipResolver struct { cc resolver.ClientConn @@ -148,12 +194,15 @@ func (i *ipResolver) watcher() { // dnsResolver watches for the name resolution update for a non-IP target. type dnsResolver struct { - freq time.Duration - host string - port string - ctx context.Context - cancel context.CancelFunc - cc resolver.ClientConn + freq time.Duration + backoff backoff.Exponential + retryCount int + host string + port string + resolver netResolver + ctx context.Context + cancel context.CancelFunc + cc resolver.ClientConn // rn channel is used by ResolveNow() to force an immediate resolution of the target. rn chan struct{} t *time.Timer @@ -192,8 +241,15 @@ func (d *dnsResolver) watcher() { case <-d.rn: } result, sc := d.lookup() - // Next lookup should happen after an interval defined by d.freq. - d.t.Reset(d.freq) + // Next lookup should happen within an interval defined by d.freq. It may be + // more often due to exponential retry on empty address list. + if len(result) == 0 { + d.retryCount++ + d.t.Reset(d.backoff.Backoff(d.retryCount)) + } else { + d.retryCount = 0 + d.t.Reset(d.freq) + } d.cc.NewServiceConfig(sc) d.cc.NewAddress(result) } @@ -201,13 +257,13 @@ func (d *dnsResolver) watcher() { func (d *dnsResolver) lookupSRV() []resolver.Address { var newAddrs []resolver.Address - _, srvs, err := lookupSRV(d.ctx, "grpclb", "tcp", d.host) + _, srvs, err := d.resolver.LookupSRV(d.ctx, "grpclb", "tcp", d.host) if err != nil { grpclog.Infof("grpc: failed dns SRV record lookup due to %v.\n", err) return nil } for _, s := range srvs { - lbAddrs, err := lookupHost(d.ctx, s.Target) + lbAddrs, err := d.resolver.LookupHost(d.ctx, s.Target) if err != nil { grpclog.Infof("grpc: failed load balancer address dns lookup due to %v.\n", err) continue @@ -226,7 +282,7 @@ func (d *dnsResolver) lookupSRV() []resolver.Address { } func (d *dnsResolver) lookupTXT() string { - ss, err := lookupTXT(d.ctx, d.host) + ss, err := d.resolver.LookupTXT(d.ctx, d.host) if err != nil { grpclog.Infof("grpc: failed dns TXT record lookup due to %v.\n", err) return "" @@ -246,7 +302,7 @@ func (d *dnsResolver) lookupTXT() string { func (d *dnsResolver) lookupHost() []resolver.Address { var newAddrs []resolver.Address - addrs, err := lookupHost(d.ctx, d.host) + addrs, err := d.resolver.LookupHost(d.ctx, d.host) if err != nil { grpclog.Warningf("grpc: failed dns A record lookup due to %v.\n", err) return nil @@ -288,17 +344,16 @@ func formatIP(addr string) (addrIP string, ok bool) { return "[" + addr + "]", true } -// parseTarget takes the user input target string, returns formatted host and port info. +// parseTarget takes the user input target string and default port, returns formatted host and port info. // If target doesn't specify a port, set the port to be the defaultPort. // If target is in IPv6 format and host-name is enclosed in sqarue brackets, brackets // are strippd when setting the host. // examples: -// target: "www.google.com" returns host: "www.google.com", port: "443" -// target: "ipv4-host:80" returns host: "ipv4-host", port: "80" -// target: "[ipv6-host]" returns host: "ipv6-host", port: "443" -// target: ":80" returns host: "localhost", port: "80" -// target: ":" returns host: "localhost", port: "443" -func parseTarget(target string) (host, port string, err error) { +// target: "www.google.com" defaultPort: "443" returns host: "www.google.com", port: "443" +// target: "ipv4-host:80" defaultPort: "443" returns host: "ipv4-host", port: "80" +// target: "[ipv6-host]" defaultPort: "443" returns host: "ipv6-host", port: "443" +// target: ":80" defaultPort: "443" returns host: "localhost", port: "80" +func parseTarget(target, defaultPort string) (host, port string, err error) { if target == "" { return "", "", errMissingAddr } @@ -307,15 +362,15 @@ func parseTarget(target string) (host, port string, err error) { return target, defaultPort, nil } if host, port, err = net.SplitHostPort(target); err == nil { + if port == "" { + // If the port field is empty (target ends with colon), e.g. "[::1]:", this is an error. + return "", "", errEndsWithColon + } // target has port, i.e ipv4-host:port, [ipv6-host]:port, host-name:port if host == "" { // Keep consistent with net.Dial(): If the host is empty, as in ":80", the local system is assumed. host = "localhost" } - if port == "" { - // If the port field is empty(target ends with colon), e.g. "[::1]:", defaultPort is used. - port = defaultPort - } return host, port, nil } if host, port, err = net.SplitHostPort(target + ":" + defaultPort); err == nil { diff --git a/vendor/google.golang.org/grpc/resolver/dns/dns_resolver_test.go b/vendor/google.golang.org/grpc/resolver/dns/dns_resolver_test.go index 66c9735f76130e331d9777acd83f4cc5d710fa89..07673d0daec6ac90a41055a75c4ddf2f3d2d3014 100644 --- a/vendor/google.golang.org/grpc/resolver/dns/dns_resolver_test.go +++ b/vendor/google.golang.org/grpc/resolver/dns/dns_resolver_test.go @@ -1,6 +1,6 @@ /* * - * Copyright 2017 gRPC authors. + * Copyright 2018 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,8 @@ package dns import ( + "context" + "errors" "fmt" "net" "os" @@ -46,7 +48,7 @@ type testClientConn struct { target string m1 sync.Mutex addrs []resolver.Address - a int + a int // how many times NewAddress() has been called m2 sync.Mutex sc string s int @@ -78,6 +80,30 @@ func (t *testClientConn) getSc() (string, int) { return t.sc, t.s } +type testResolver struct { +} + +func (*testResolver) LookupHost(ctx context.Context, host string) ([]string, error) { + return hostLookup(host) +} + +func (*testResolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*net.SRV, error) { + return srvLookup(service, proto, name) +} + +func (*testResolver) LookupTXT(ctx context.Context, host string) ([]string, error) { + return txtLookup(host) +} + +func replaceNetFunc() func() { + oldResolver := defaultResolver + defaultResolver = &testResolver{} + + return func() { + defaultResolver = oldResolver + } +} + var hostLookupTbl = struct { sync.Mutex tbl map[string][]string @@ -815,7 +841,7 @@ func testIPResolver(t *testing.T) { {"127.0.0.1:12345", []resolver.Address{{Addr: "127.0.0.1:12345"}}}, {"::1", []resolver.Address{{Addr: "[::1]" + colonDefaultPort}}}, {"[::1]:12345", []resolver.Address{{Addr: "[::1]:12345"}}}, - {"[::1]:", []resolver.Address{{Addr: "[::1]:443"}}}, + {"[::1]", []resolver.Address{{Addr: "[::1]:443"}}}, {"2001:db8:85a3::8a2e:370:7334", []resolver.Address{{Addr: "[2001:db8:85a3::8a2e:370:7334]" + colonDefaultPort}}}, {"[2001:db8:85a3::8a2e:370:7334]", []resolver.Address{{Addr: "[2001:db8:85a3::8a2e:370:7334]" + colonDefaultPort}}}, {"[2001:db8:85a3::8a2e:370:7334]:12345", []resolver.Address{{Addr: "[2001:db8:85a3::8a2e:370:7334]:12345"}}}, @@ -867,6 +893,7 @@ func TestResolveFunc(t *testing.T) { {"www.google.com", nil}, {"foo.bar:12345", nil}, {"127.0.0.1", nil}, + {"::", nil}, {"127.0.0.1:12345", nil}, {"[::1]:80", nil}, {"[2001:db8:a0b:12f0::1]:21", nil}, @@ -875,9 +902,10 @@ func TestResolveFunc(t *testing.T) { {"[fe80::1%lo0]:80", nil}, {"golang.org:http", nil}, {"[2001:db8::1]:http", nil}, - {":", nil}, + {"[2001:db8::1]:", errEndsWithColon}, + {":", errEndsWithColon}, {"", errMissingAddr}, - {"[2001:db8:a0b:12f0::1", errForInvalidTarget}, + {"[2001:db8:a0b:12f0::1", fmt.Errorf("invalid target address [2001:db8:a0b:12f0::1, error info: address [2001:db8:a0b:12f0::1:443: missing ']' in address")}, } b := NewBuilder() @@ -934,3 +962,163 @@ func TestDisableServiceConfig(t *testing.T) { r.Close() } } + +func TestDNSResolverRetry(t *testing.T) { + b := NewBuilder() + target := "ipv4.single.fake" + cc := &testClientConn{target: target} + r, err := b.Build(resolver.Target{Endpoint: target}, cc, resolver.BuildOption{}) + if err != nil { + t.Fatalf("%v\n", err) + } + var addrs []resolver.Address + for { + addrs, _ = cc.getAddress() + if len(addrs) == 1 { + break + } + time.Sleep(time.Millisecond) + } + want := []resolver.Address{{Addr: "1.2.3.4" + colonDefaultPort}} + if !reflect.DeepEqual(want, addrs) { + t.Errorf("Resolved addresses of target: %q = %+v, want %+v\n", target, addrs, want) + } + // mutate the host lookup table so the target has 0 address returned. + revertTbl := mutateTbl(target) + // trigger a resolve that will get empty address list + r.ResolveNow(resolver.ResolveNowOption{}) + for { + addrs, _ = cc.getAddress() + if len(addrs) == 0 { + break + } + time.Sleep(time.Millisecond) + } + revertTbl() + // wait for the retry to happen in two seconds. + timer := time.NewTimer(2 * time.Second) + for { + b := false + select { + case <-timer.C: + b = true + default: + addrs, _ = cc.getAddress() + if len(addrs) == 1 { + b = true + break + } + time.Sleep(time.Millisecond) + } + if b { + break + } + } + if !reflect.DeepEqual(want, addrs) { + t.Errorf("Resolved addresses of target: %q = %+v, want %+v\n", target, addrs, want) + } + r.Close() +} + +func TestCustomAuthority(t *testing.T) { + defer leakcheck.Check(t) + + tests := []struct { + authority string + authorityWant string + expectError bool + }{ + { + "4.3.2.1:" + defaultDNSSvrPort, + "4.3.2.1:" + defaultDNSSvrPort, + false, + }, + { + "4.3.2.1:123", + "4.3.2.1:123", + false, + }, + { + "4.3.2.1", + "4.3.2.1:" + defaultDNSSvrPort, + false, + }, + { + "::1", + "[::1]:" + defaultDNSSvrPort, + false, + }, + { + "[::1]", + "[::1]:" + defaultDNSSvrPort, + false, + }, + { + "[::1]:123", + "[::1]:123", + false, + }, + { + "dnsserver.com", + "dnsserver.com:" + defaultDNSSvrPort, + false, + }, + { + ":123", + "localhost:123", + false, + }, + { + ":", + "", + true, + }, + { + "[::1]:", + "", + true, + }, + { + "dnsserver.com:", + "", + true, + }, + } + oldCustomAuthorityDialler := customAuthorityDialler + defer func() { + customAuthorityDialler = oldCustomAuthorityDialler + }() + + for _, a := range tests { + errChan := make(chan error, 1) + customAuthorityDialler = func(authority string) func(ctx context.Context, network, address string) (net.Conn, error) { + if authority != a.authorityWant { + errChan <- fmt.Errorf("wrong custom authority passed to resolver. input: %s expected: %s actual: %s", a.authority, a.authorityWant, authority) + } else { + errChan <- nil + } + return func(ctx context.Context, network, address string) (net.Conn, error) { + return nil, errors.New("no need to dial") + } + } + + b := NewBuilder() + cc := &testClientConn{target: "foo.bar.com"} + r, err := b.Build(resolver.Target{Endpoint: "foo.bar.com", Authority: a.authority}, cc, resolver.BuildOption{}) + + if err == nil { + r.Close() + + err = <-errChan + if err != nil { + t.Errorf(err.Error()) + } + + if a.expectError { + t.Errorf("custom authority should have caused an error: %s", a.authority) + } + } else if !a.expectError { + t.Errorf("unexpected error using custom authority %s: %s", a.authority, err) + } + } +} diff --git a/vendor/google.golang.org/grpc/resolver/dns/go17.go b/vendor/google.golang.org/grpc/resolver/dns/go17.go deleted file mode 100644 index b466bc8f6d456fd48460b76d4f084195e215d38a..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/resolver/dns/go17.go +++ /dev/null @@ -1,35 +0,0 @@ -// +build go1.6, !go1.8 - -/* - * - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package dns - -import ( - "net" - - "golang.org/x/net/context" -) - -var ( - lookupHost = func(ctx context.Context, host string) ([]string, error) { return net.LookupHost(host) } - lookupSRV = func(ctx context.Context, service, proto, name string) (string, []*net.SRV, error) { - return net.LookupSRV(service, proto, name) - } - lookupTXT = func(ctx context.Context, name string) ([]string, error) { return net.LookupTXT(name) } -) diff --git a/vendor/google.golang.org/grpc/resolver/dns/go17_test.go b/vendor/google.golang.org/grpc/resolver/dns/go17_test.go deleted file mode 100644 index 21eaa8885c7ad63520255af17d759ade518d0dc7..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/resolver/dns/go17_test.go +++ /dev/null @@ -1,50 +0,0 @@ -// +build go1.6, !go1.8 - -/* - * - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package dns - -import ( - "fmt" - "net" - - "golang.org/x/net/context" -) - -var errForInvalidTarget = fmt.Errorf("invalid target address [2001:db8:a0b:12f0::1, error info: missing ']' in address [2001:db8:a0b:12f0::1:443") - -func replaceNetFunc() func() { - oldLookupHost := lookupHost - oldLookupSRV := lookupSRV - oldLookupTXT := lookupTXT - lookupHost = func(ctx context.Context, host string) ([]string, error) { - return hostLookup(host) - } - lookupSRV = func(ctx context.Context, service, proto, name string) (string, []*net.SRV, error) { - return srvLookup(service, proto, name) - } - lookupTXT = func(ctx context.Context, host string) ([]string, error) { - return txtLookup(host) - } - return func() { - lookupHost = oldLookupHost - lookupSRV = oldLookupSRV - lookupTXT = oldLookupTXT - } -} diff --git a/vendor/google.golang.org/grpc/resolver/dns/go18_test.go b/vendor/google.golang.org/grpc/resolver/dns/go18_test.go deleted file mode 100644 index b0149c86770949dacb7c06d9f4c8b06c25c5e83a..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/resolver/dns/go18_test.go +++ /dev/null @@ -1,49 +0,0 @@ -// +build go1.8 - -/* - * - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package dns - -import ( - "context" - "fmt" - "net" -) - -var errForInvalidTarget = fmt.Errorf("invalid target address [2001:db8:a0b:12f0::1, error info: address [2001:db8:a0b:12f0::1:443: missing ']' in address") - -func replaceNetFunc() func() { - oldLookupHost := lookupHost - oldLookupSRV := lookupSRV - oldLookupTXT := lookupTXT - lookupHost = func(ctx context.Context, host string) ([]string, error) { - return hostLookup(host) - } - lookupSRV = func(ctx context.Context, service, proto, name string) (string, []*net.SRV, error) { - return srvLookup(service, proto, name) - } - lookupTXT = func(ctx context.Context, host string) ([]string, error) { - return txtLookup(host) - } - return func() { - lookupHost = oldLookupHost - lookupSRV = oldLookupSRV - lookupTXT = oldLookupTXT - } -} diff --git a/vendor/google.golang.org/grpc/resolver/resolver.go b/vendor/google.golang.org/grpc/resolver/resolver.go index 506afac88aea2446f2d77169de22d7c4e84190f3..145cf477edb09bfa11741540f6565bf30f7e1989 100644 --- a/vendor/google.golang.org/grpc/resolver/resolver.go +++ b/vendor/google.golang.org/grpc/resolver/resolver.go @@ -49,8 +49,12 @@ func Get(scheme string) Builder { return nil } -// SetDefaultScheme sets the default scheme that will be used. -// The default default scheme is "passthrough". +// SetDefaultScheme sets the default scheme that will be used. The default +// default scheme is "passthrough". +// +// NOTE: this function must only be called during initialization time (i.e. in +// an init() function), and is not thread-safe. The scheme set last overrides +// previously set values. func SetDefaultScheme(scheme string) { defaultScheme = scheme } diff --git a/vendor/google.golang.org/grpc/resolver_conn_wrapper.go b/vendor/google.golang.org/grpc/resolver_conn_wrapper.go index 494d6931ebb5db86b5c3a3cd45f8689847e9a1ea..9d7602539fba707313fb574f46c7695e40ee9f62 100644 --- a/vendor/google.golang.org/grpc/resolver_conn_wrapper.go +++ b/vendor/google.golang.org/grpc/resolver_conn_wrapper.go @@ -23,17 +23,19 @@ import ( "strings" "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/internal/channelz" "google.golang.org/grpc/resolver" ) // ccResolverWrapper is a wrapper on top of cc for resolvers. // It implements resolver.ClientConnection interface. type ccResolverWrapper struct { - cc *ClientConn - resolver resolver.Resolver - addrCh chan []resolver.Address - scCh chan string - done chan struct{} + cc *ClientConn + resolver resolver.Resolver + addrCh chan []resolver.Address + scCh chan string + done chan struct{} + lastAddressesCount int } // split2 returns the values from strings.SplitN(s, sep, 2). @@ -91,44 +93,6 @@ func newCCResolverWrapper(cc *ClientConn) (*ccResolverWrapper, error) { return ccr, nil } -func (ccr *ccResolverWrapper) start() { - go ccr.watcher() -} - -// watcher processes address updates and service config updates sequentially. -// Otherwise, we need to resolve possible races between address and service -// config (e.g. they specify different balancer types). -func (ccr *ccResolverWrapper) watcher() { - for { - select { - case <-ccr.done: - return - default: - } - - select { - case addrs := <-ccr.addrCh: - select { - case <-ccr.done: - return - default: - } - grpclog.Infof("ccResolverWrapper: sending new addresses to cc: %v", addrs) - ccr.cc.handleResolvedAddrs(addrs, nil) - case sc := <-ccr.scCh: - select { - case <-ccr.done: - return - default: - } - grpclog.Infof("ccResolverWrapper: got new service config: %v", sc) - ccr.cc.handleServiceConfig(sc) - case <-ccr.done: - return - } - } -} - func (ccr *ccResolverWrapper) resolveNow(o resolver.ResolveNowOption) { ccr.resolver.ResolveNow(o) } @@ -141,18 +105,51 @@ func (ccr *ccResolverWrapper) close() { // NewAddress is called by the resolver implemenetion to send addresses to gRPC. func (ccr *ccResolverWrapper) NewAddress(addrs []resolver.Address) { select { - case <-ccr.addrCh: + case <-ccr.done: + return default: } - ccr.addrCh <- addrs + grpclog.Infof("ccResolverWrapper: sending new addresses to cc: %v", addrs) + if channelz.IsOn() { + ccr.addChannelzTraceEvent(addrs) + } + ccr.cc.handleResolvedAddrs(addrs, nil) } // NewServiceConfig is called by the resolver implemenetion to send service // configs to gRPC. func (ccr *ccResolverWrapper) NewServiceConfig(sc string) { select { - case <-ccr.scCh: + case <-ccr.done: + return default: } - ccr.scCh <- sc + grpclog.Infof("ccResolverWrapper: got new service config: %v", sc) + ccr.cc.handleServiceConfig(sc) +} + +func (ccr *ccResolverWrapper) addChannelzTraceEvent(addrs []resolver.Address) { + if len(addrs) == 0 && ccr.lastAddressesCount != 0 { + channelz.AddTraceEvent(ccr.cc.channelzID, &channelz.TraceEventDesc{ + Desc: "Resolver returns an empty address list", + Severity: channelz.CtWarning, + }) + } else if len(addrs) != 0 && ccr.lastAddressesCount == 0 { + var s string + for i, a := range addrs { + if a.ServerName != "" { + s += a.Addr + "(" + a.ServerName + ")" + } else { + s += a.Addr + } + if i != len(addrs)-1 { + s += " " + } + } + channelz.AddTraceEvent(ccr.cc.channelzID, &channelz.TraceEventDesc{ + Desc: fmt.Sprintf("Resolver returns a non-empty address list (previous one was empty) %q", s), + Severity: channelz.CtINFO, + }) + } + ccr.lastAddressesCount = len(addrs) } diff --git a/vendor/google.golang.org/grpc/resolver_conn_wrapper_test.go b/vendor/google.golang.org/grpc/resolver_conn_wrapper_test.go index 6f1367a2cedbb5716761aa1468ce4df4625fd0d6..e87b94200c64cbcc5ff6088941978a9574419f9b 100644 --- a/vendor/google.golang.org/grpc/resolver_conn_wrapper_test.go +++ b/vendor/google.golang.org/grpc/resolver_conn_wrapper_test.go @@ -97,8 +97,11 @@ func TestDialParseTargetUnknownScheme(t *testing.T) { {"passthrough://a.server.com/google.com", "google.com"}, } { dialStrCh := make(chan string, 1) - cc, err := Dial(test.targetStr, WithInsecure(), WithDialer(func(t string, _ time.Duration) (net.Conn, error) { - dialStrCh <- t + cc, err := Dial(test.targetStr, WithInsecure(), WithDialer(func(addr string, _ time.Duration) (net.Conn, error) { + select { + case dialStrCh <- addr: + default: + } return nil, fmt.Errorf("test dialer, always error") })) if err != nil { diff --git a/vendor/google.golang.org/grpc/rpc_util.go b/vendor/google.golang.org/grpc/rpc_util.go index 033801f34f8d08172580fd5836b340e99b196e70..86f00e5a2d1ff0e10e4b4059cf5d4ed85da81427 100644 --- a/vendor/google.golang.org/grpc/rpc_util.go +++ b/vendor/google.golang.org/grpc/rpc_util.go @@ -21,6 +21,7 @@ package grpc import ( "bytes" "compress/gzip" + "context" "encoding/binary" "fmt" "io" @@ -31,16 +32,15 @@ import ( "sync" "time" - "golang.org/x/net/context" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/encoding" "google.golang.org/grpc/encoding/proto" + "google.golang.org/grpc/internal/transport" "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" "google.golang.org/grpc/stats" "google.golang.org/grpc/status" - "google.golang.org/grpc/transport" ) // Compressor defines the interface gRPC uses to compress a message. @@ -155,17 +155,20 @@ func (d *gzipDecompressor) Type() string { type callInfo struct { compressorType string failFast bool - stream *clientStream - traceInfo traceInfo // in trace.go + stream ClientStream maxReceiveMessageSize *int maxSendMessageSize *int creds credentials.PerRPCCredentials contentSubtype string codec baseCodec + maxRetryRPCBufferSize int } func defaultCallInfo() *callInfo { - return &callInfo{failFast: true} + return &callInfo{ + failFast: true, + maxRetryRPCBufferSize: 256 * 1024, // 256KB + } } // CallOption configures a Call before it starts or extracts information from @@ -415,6 +418,27 @@ func (o CustomCodecCallOption) before(c *callInfo) error { } func (o CustomCodecCallOption) after(c *callInfo) {} +// MaxRetryRPCBufferSize returns a CallOption that limits the amount of memory +// used for buffering this RPC's requests for retry purposes. +// +// This API is EXPERIMENTAL. +func MaxRetryRPCBufferSize(bytes int) CallOption { + return MaxRetryRPCBufferSizeCallOption{bytes} +} + +// MaxRetryRPCBufferSizeCallOption is a CallOption indicating the amount of +// memory to be used for caching this RPC for retry purposes. +// This is an EXPERIMENTAL API. +type MaxRetryRPCBufferSizeCallOption struct { + MaxRetryRPCBufferSize int +} + +func (o MaxRetryRPCBufferSizeCallOption) before(c *callInfo) error { + c.maxRetryRPCBufferSize = o.MaxRetryRPCBufferSize + return nil +} +func (o MaxRetryRPCBufferSizeCallOption) after(c *callInfo) {} + // The format of the payload: compressed or not? type payloadFormat uint8 @@ -444,7 +468,7 @@ type parser struct { // * io.EOF, when no messages remain // * io.ErrUnexpectedEOF // * of type transport.ConnectionError -// * of type transport.StreamError +// * an error from the status package // No other error values or types must be returned, which also means // that the underlying io.Reader must not return an incompatible // error. @@ -507,7 +531,10 @@ func compress(in []byte, cp Compressor, compressor encoding.Compressor) ([]byte, } cbuf := &bytes.Buffer{} if compressor != nil { - z, _ := compressor.Compress(cbuf) + z, err := compressor.Compress(cbuf) + if err != nil { + return nil, wrapErr(err) + } if _, err := z.Write(in); err != nil { return nil, wrapErr(err) } @@ -571,20 +598,22 @@ func checkRecvPayload(pf payloadFormat, recvCompress string, haveCompressor bool return nil } -// For the two compressor parameters, both should not be set, but if they are, -// dc takes precedence over compressor. -// TODO(dfawley): wrap the old compressor/decompressor using the new API? -func recv(p *parser, c baseCodec, s *transport.Stream, dc Decompressor, m interface{}, maxReceiveMessageSize int, inPayload *stats.InPayload, compressor encoding.Compressor) error { +type payloadInfo struct { + wireLength int // The compressed length got from wire. + uncompressedBytes []byte +} + +func recvAndDecompress(p *parser, s *transport.Stream, dc Decompressor, maxReceiveMessageSize int, payInfo *payloadInfo, compressor encoding.Compressor) ([]byte, error) { pf, d, err := p.recvMsg(maxReceiveMessageSize) if err != nil { - return err + return nil, err } - if inPayload != nil { - inPayload.WireLength = len(d) + if payInfo != nil { + payInfo.wireLength = len(d) } if st := checkRecvPayload(pf, s.RecvCompress(), compressor != nil || dc != nil); st != nil { - return st.Err() + return nil, st.Err() } if pf == compressionMade { @@ -593,33 +622,40 @@ func recv(p *parser, c baseCodec, s *transport.Stream, dc Decompressor, m interf if dc != nil { d, err = dc.Do(bytes.NewReader(d)) if err != nil { - return status.Errorf(codes.Internal, "grpc: failed to decompress the received message %v", err) + return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message %v", err) } } else { dcReader, err := compressor.Decompress(bytes.NewReader(d)) if err != nil { - return status.Errorf(codes.Internal, "grpc: failed to decompress the received message %v", err) + return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message %v", err) } d, err = ioutil.ReadAll(dcReader) if err != nil { - return status.Errorf(codes.Internal, "grpc: failed to decompress the received message %v", err) + return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message %v", err) } } } if len(d) > maxReceiveMessageSize { // TODO: Revisit the error code. Currently keep it consistent with java // implementation. - return status.Errorf(codes.ResourceExhausted, "grpc: received message larger than max (%d vs. %d)", len(d), maxReceiveMessageSize) + return nil, status.Errorf(codes.ResourceExhausted, "grpc: received message larger than max (%d vs. %d)", len(d), maxReceiveMessageSize) + } + return d, nil +} + +// For the two compressor parameters, both should not be set, but if they are, +// dc takes precedence over compressor. +// TODO(dfawley): wrap the old compressor/decompressor using the new API? +func recv(p *parser, c baseCodec, s *transport.Stream, dc Decompressor, m interface{}, maxReceiveMessageSize int, payInfo *payloadInfo, compressor encoding.Compressor) error { + d, err := recvAndDecompress(p, s, dc, maxReceiveMessageSize, payInfo, compressor) + if err != nil { + return err } if err := c.Unmarshal(d, m); err != nil { return status.Errorf(codes.Internal, "grpc: failed to unmarshal the received message %v", err) } - if inPayload != nil { - inPayload.RecvTime = time.Now() - inPayload.Payload = m - // TODO truncate large payload. - inPayload.Data = d - inPayload.Length = len(d) + if payInfo != nil { + payInfo.uncompressedBytes = d } return nil } @@ -669,6 +705,31 @@ func Errorf(c codes.Code, format string, a ...interface{}) error { return status.Errorf(c, format, a...) } +// toRPCErr converts an error into an error from the status package. +func toRPCErr(err error) error { + if err == nil || err == io.EOF { + return err + } + if err == io.ErrUnexpectedEOF { + return status.Error(codes.Internal, err.Error()) + } + if _, ok := status.FromError(err); ok { + return err + } + switch e := err.(type) { + case transport.ConnectionError: + return status.Error(codes.Unavailable, e.Desc) + default: + switch err { + case context.DeadlineExceeded: + return status.Error(codes.DeadlineExceeded, err.Error()) + case context.Canceled: + return status.Error(codes.Canceled, err.Error()) + } + } + return status.Error(codes.Unknown, err.Error()) +} + // setCallInfoCodec should only be called after CallOptions have been applied. func setCallInfoCodec(c *callInfo) error { if c.codec != nil { @@ -724,6 +785,19 @@ func parseDialTarget(target string) (net string, addr string) { return net, target } +// channelzData is used to store channelz related data for ClientConn, addrConn and Server. +// These fields cannot be embedded in the original structs (e.g. ClientConn), since to do atomic +// operation on int64 variable on 32-bit machine, user is responsible to enforce memory alignment. +// Here, by grouping those int64 fields inside a struct, we are enforcing the alignment. +type channelzData struct { + callsStarted int64 + callsFailed int64 + callsSucceeded int64 + // lastCallStartedTime stores the timestamp that last call starts. It is of int64 type instead of + // time.Time since it's more costly to atomically update time.Time variable than int64 variable. + lastCallStartedTime int64 +} + // The SupportPackageIsVersion variables are referenced from generated protocol // buffer files to ensure compatibility with the gRPC version used. The latest // support package version is 5. diff --git a/vendor/google.golang.org/grpc/rpc_util_test.go b/vendor/google.golang.org/grpc/rpc_util_test.go index f28cff2333b8a6115cb3b0186e09cfcb35bc7fe3..0335fc7d2dc9508e3fbf375a792ee850bff54248 100644 --- a/vendor/google.golang.org/grpc/rpc_util_test.go +++ b/vendor/google.golang.org/grpc/rpc_util_test.go @@ -30,9 +30,9 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/encoding" protoenc "google.golang.org/grpc/encoding/proto" + "google.golang.org/grpc/internal/transport" "google.golang.org/grpc/status" perfpb "google.golang.org/grpc/test/codec_perf" - "google.golang.org/grpc/transport" ) type fullReader struct { @@ -177,8 +177,8 @@ func TestToRPCErr(t *testing.T) { // outputs errOut error }{ - {transport.StreamError{Code: codes.Unknown, Desc: ""}, status.Error(codes.Unknown, "")}, {transport.ErrConnClosing, status.Error(codes.Unavailable, transport.ErrConnClosing.Desc)}, + {io.ErrUnexpectedEOF, status.Error(codes.Internal, io.ErrUnexpectedEOF.Error())}, } { err := toRPCErr(test.errIn) if _, ok := status.FromError(err); !ok { diff --git a/vendor/google.golang.org/grpc/server.go b/vendor/google.golang.org/grpc/server.go index 014c72b3f2834f630d545e3cd66384b9c11d916f..d705d7a80cd1c484829f40828cd219f2ee5cc92f 100644 --- a/vendor/google.golang.org/grpc/server.go +++ b/vendor/google.golang.org/grpc/server.go @@ -19,7 +19,7 @@ package grpc import ( - "bytes" + "context" "errors" "fmt" "io" @@ -30,12 +30,9 @@ import ( "runtime" "strings" "sync" + "sync/atomic" "time" - "io/ioutil" - - "golang.org/x/net/context" - "golang.org/x/net/http2" "golang.org/x/net/trace" "google.golang.org/grpc/codes" @@ -43,14 +40,15 @@ import ( "google.golang.org/grpc/encoding" "google.golang.org/grpc/encoding/proto" "google.golang.org/grpc/grpclog" - "google.golang.org/grpc/internal" + "google.golang.org/grpc/internal/binarylog" "google.golang.org/grpc/internal/channelz" + "google.golang.org/grpc/internal/transport" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/metadata" + "google.golang.org/grpc/peer" "google.golang.org/grpc/stats" "google.golang.org/grpc/status" "google.golang.org/grpc/tap" - "google.golang.org/grpc/transport" ) const ( @@ -106,12 +104,8 @@ type Server struct { channelzRemoveOnce sync.Once serveWG sync.WaitGroup // counts active Serve goroutines for GracefulStop - channelzID int64 // channelz unique identification number - czmu sync.RWMutex - callsStarted int64 - callsFailed int64 - callsSucceeded int64 - lastCallStartedTime time.Time + channelzID int64 // channelz unique identification number + czData *channelzData } type options struct { @@ -126,7 +120,6 @@ type options struct { maxConcurrentStreams uint32 maxReceiveMessageSize int maxSendMessageSize int - useHandlerImpl bool // use http.Handler-based server unknownStreamDesc *StreamDesc keepaliveParams keepalive.ServerParameters keepalivePolicy keepalive.EnforcementPolicy @@ -135,19 +128,25 @@ type options struct { writeBufferSize int readBufferSize int connectionTimeout time.Duration + maxHeaderListSize *uint32 } var defaultServerOptions = options{ maxReceiveMessageSize: defaultServerMaxReceiveMessageSize, maxSendMessageSize: defaultServerMaxSendMessageSize, connectionTimeout: 120 * time.Second, + writeBufferSize: defaultWriteBufSize, + readBufferSize: defaultReadBufSize, } // A ServerOption sets options such as credentials, codec and keepalive parameters, etc. type ServerOption func(*options) -// WriteBufferSize lets you set the size of write buffer, this determines how much data can be batched -// before doing a write on the wire. +// WriteBufferSize determines how much data can be batched before doing a write on the wire. +// The corresponding memory allocation for this buffer will be twice the size to keep syscalls low. +// The default value for this buffer is 32KB. +// Zero will disable the write buffer such that each write will be on underlying connection. +// Note: A Send call may not directly translate to a write. func WriteBufferSize(s int) ServerOption { return func(o *options) { o.writeBufferSize = s @@ -156,6 +155,9 @@ func WriteBufferSize(s int) ServerOption { // ReadBufferSize lets you set the size of read buffer, this determines how much data can be read at most // for one read syscall. +// The default value for this buffer is 32KB. +// Zero will disable read buffer for a connection so data framer can access the underlying +// conn directly. func ReadBufferSize(s int) ServerOption { return func(o *options) { o.readBufferSize = s @@ -335,6 +337,14 @@ func ConnectionTimeout(d time.Duration) ServerOption { } } +// MaxHeaderListSize returns a ServerOption that sets the max (uncompressed) size +// of header list that the server is prepared to accept. +func MaxHeaderListSize(s uint32) ServerOption { + return func(o *options) { + o.maxHeaderListSize = &s + } +} + // NewServer creates a gRPC server which has no service registered and has not // started to accept requests yet. func NewServer(opt ...ServerOption) *Server { @@ -343,12 +353,13 @@ func NewServer(opt ...ServerOption) *Server { o(&opts) } s := &Server{ - lis: make(map[net.Listener]bool), - opts: opts, - conns: make(map[io.Closer]bool), - m: make(map[string]*service), - quit: make(chan struct{}), - done: make(chan struct{}), + lis: make(map[net.Listener]bool), + opts: opts, + conns: make(map[io.Closer]bool), + m: make(map[string]*service), + quit: make(chan struct{}), + done: make(chan struct{}), + czData: new(channelzData), } s.cv = sync.NewCond(&s.mu) if EnableTracing { @@ -357,7 +368,7 @@ func NewServer(opt ...ServerOption) *Server { } if channelz.IsOn() { - s.channelzID = channelz.RegisterServer(s, "") + s.channelzID = channelz.RegisterServer(&channelzServer{s}, "") } return s } @@ -481,7 +492,8 @@ type listenSocket struct { func (l *listenSocket) ChannelzMetric() *channelz.SocketInternalMetric { return &channelz.SocketInternalMetric{ - LocalAddr: l.Listener.Addr(), + SocketOptions: channelz.GetSocketOption(l.Listener), + LocalAddr: l.Listener.Addr(), } } @@ -525,7 +537,7 @@ func (s *Server) Serve(lis net.Listener) error { s.lis[ls] = true if channelz.IsOn() { - ls.channelzID = channelz.RegisterListenSocket(ls, s.channelzID, "") + ls.channelzID = channelz.RegisterListenSocket(ls, s.channelzID, lis.Addr().String()) } s.mu.Unlock() @@ -617,27 +629,19 @@ func (s *Server) handleRawConn(rawConn net.Conn) { } s.mu.Unlock() - var serve func() - c := conn.(io.Closer) - if s.opts.useHandlerImpl { - serve = func() { s.serveUsingHandler(conn) } - } else { - // Finish handshaking (HTTP2) - st := s.newHTTP2Transport(conn, authInfo) - if st == nil { - return - } - c = st - serve = func() { s.serveStreams(st) } + // Finish handshaking (HTTP2) + st := s.newHTTP2Transport(conn, authInfo) + if st == nil { + return } rawConn.SetDeadline(time.Time{}) - if !s.addConn(c) { + if !s.addConn(st) { return } go func() { - serve() - s.removeConn(c) + s.serveStreams(st) + s.removeConn(st) }() } @@ -656,6 +660,7 @@ func (s *Server) newHTTP2Transport(c net.Conn, authInfo credentials.AuthInfo) tr WriteBufferSize: s.opts.writeBufferSize, ReadBufferSize: s.opts.readBufferSize, ChannelzParentID: s.channelzID, + MaxHeaderListSize: s.opts.maxHeaderListSize, } st, err := transport.NewServerTransport("http2", c, config) if err != nil { @@ -691,27 +696,6 @@ func (s *Server) serveStreams(st transport.ServerTransport) { var _ http.Handler = (*Server)(nil) -// serveUsingHandler is called from handleRawConn when s is configured -// to handle requests via the http.Handler interface. It sets up a -// net/http.Server to handle the just-accepted conn. The http.Server -// is configured to route all incoming requests (all HTTP/2 streams) -// to ServeHTTP, which creates a new ServerTransport for each stream. -// serveUsingHandler blocks until conn closes. -// -// This codepath is only used when Server.TestingUseHandlerImpl has -// been configured. This lets the end2end tests exercise the ServeHTTP -// method as one of the environment types. -// -// conn is the *tls.Conn that's already been authenticated. -func (s *Server) serveUsingHandler(conn net.Conn) { - h2s := &http2.Server{ - MaxConcurrentStreams: s.opts.maxConcurrentStreams, - } - h2s.ServeConn(conn, &http2.ServeConnOpts{ - Handler: s, - }) -} - // ServeHTTP implements the Go standard library's http.Handler // interface by responding to the gRPC request r, by looking up // the requested gRPC method in the gRPC server s. @@ -794,36 +778,26 @@ func (s *Server) removeConn(c io.Closer) { } } -// ChannelzMetric returns ServerInternalMetric of current server. -// This is an EXPERIMENTAL API. -func (s *Server) ChannelzMetric() *channelz.ServerInternalMetric { - s.czmu.RLock() - defer s.czmu.RUnlock() +func (s *Server) channelzMetric() *channelz.ServerInternalMetric { return &channelz.ServerInternalMetric{ - CallsStarted: s.callsStarted, - CallsSucceeded: s.callsSucceeded, - CallsFailed: s.callsFailed, - LastCallStartedTimestamp: s.lastCallStartedTime, + CallsStarted: atomic.LoadInt64(&s.czData.callsStarted), + CallsSucceeded: atomic.LoadInt64(&s.czData.callsSucceeded), + CallsFailed: atomic.LoadInt64(&s.czData.callsFailed), + LastCallStartedTimestamp: time.Unix(0, atomic.LoadInt64(&s.czData.lastCallStartedTime)), } } func (s *Server) incrCallsStarted() { - s.czmu.Lock() - s.callsStarted++ - s.lastCallStartedTime = time.Now() - s.czmu.Unlock() + atomic.AddInt64(&s.czData.callsStarted, 1) + atomic.StoreInt64(&s.czData.lastCallStartedTime, time.Now().UnixNano()) } func (s *Server) incrCallsSucceeded() { - s.czmu.Lock() - s.callsSucceeded++ - s.czmu.Unlock() + atomic.AddInt64(&s.czData.callsSucceeded, 1) } func (s *Server) incrCallsFailed() { - s.czmu.Lock() - s.callsFailed++ - s.czmu.Unlock() + atomic.AddInt64(&s.czData.callsFailed, 1) } func (s *Server) sendResponse(t transport.ServerTransport, stream *transport.Stream, msg interface{}, cp Compressor, opts *transport.Options, comp encoding.Compressor) error { @@ -890,6 +864,30 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. }() } + binlog := binarylog.GetMethodLogger(stream.Method()) + if binlog != nil { + ctx := stream.Context() + md, _ := metadata.FromIncomingContext(ctx) + logEntry := &binarylog.ClientHeader{ + Header: md, + MethodName: stream.Method(), + PeerAddr: nil, + } + if deadline, ok := ctx.Deadline(); ok { + logEntry.Timeout = deadline.Sub(time.Now()) + if logEntry.Timeout < 0 { + logEntry.Timeout = 0 + } + } + if a := md[":authority"]; len(a) > 0 { + logEntry.Authority = a[0] + } + if peer, ok := peer.FromContext(ctx); ok { + logEntry.PeerAddr = peer.Addr + } + binlog.Log(logEntry) + } + // comp and cp are used for compression. decomp and dc are used for // decompression. If comp and decomp are both set, they are the same; // however they are kept separate to ensure that at most one of the @@ -926,81 +924,38 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. } } - p := &parser{r: stream} - pf, req, err := p.recvMsg(s.opts.maxReceiveMessageSize) - if err == io.EOF { - // The entire stream is done (for unary RPC only). - return err - } - if err == io.ErrUnexpectedEOF { - err = status.Errorf(codes.Internal, io.ErrUnexpectedEOF.Error()) + var payInfo *payloadInfo + if sh != nil || binlog != nil { + payInfo = &payloadInfo{} } + d, err := recvAndDecompress(&parser{r: stream}, stream, dc, s.opts.maxReceiveMessageSize, payInfo, decomp) if err != nil { if st, ok := status.FromError(err); ok { if e := t.WriteStatus(stream, st); e != nil { grpclog.Warningf("grpc: Server.processUnaryRPC failed to write status %v", e) } - } else { - switch st := err.(type) { - case transport.ConnectionError: - // Nothing to do here. - case transport.StreamError: - if e := t.WriteStatus(stream, status.New(st.Code, st.Desc)); e != nil { - grpclog.Warningf("grpc: Server.processUnaryRPC failed to write status %v", e) - } - default: - panic(fmt.Sprintf("grpc: Unexpected error (%T) from recvMsg: %v", st, st)) - } } return err } if channelz.IsOn() { t.IncrMsgRecv() } - if st := checkRecvPayload(pf, stream.RecvCompress(), dc != nil || decomp != nil); st != nil { - if e := t.WriteStatus(stream, st); e != nil { - grpclog.Warningf("grpc: Server.processUnaryRPC failed to write status %v", e) - } - return st.Err() - } - var inPayload *stats.InPayload - if sh != nil { - inPayload = &stats.InPayload{ - RecvTime: time.Now(), - } - } df := func(v interface{}) error { - if inPayload != nil { - inPayload.WireLength = len(req) - } - if pf == compressionMade { - var err error - if dc != nil { - req, err = dc.Do(bytes.NewReader(req)) - if err != nil { - return status.Errorf(codes.Internal, err.Error()) - } - } else { - tmp, _ := decomp.Decompress(bytes.NewReader(req)) - req, err = ioutil.ReadAll(tmp) - if err != nil { - return status.Errorf(codes.Internal, "grpc: failed to decompress the received message %v", err) - } - } - } - if len(req) > s.opts.maxReceiveMessageSize { - // TODO: Revisit the error code. Currently keep it consistent with - // java implementation. - return status.Errorf(codes.ResourceExhausted, "grpc: received message larger than max (%d vs. %d)", len(req), s.opts.maxReceiveMessageSize) - } - if err := s.getCodec(stream.ContentSubtype()).Unmarshal(req, v); err != nil { + if err := s.getCodec(stream.ContentSubtype()).Unmarshal(d, v); err != nil { return status.Errorf(codes.Internal, "grpc: error unmarshalling request: %v", err) } - if inPayload != nil { - inPayload.Payload = v - inPayload.Data = req - inPayload.Length = len(req) - sh.HandleRPC(stream.Context(), inPayload) + if sh != nil { + sh.HandleRPC(stream.Context(), &stats.InPayload{ + RecvTime: time.Now(), + Payload: v, + Data: d, + Length: len(d), + }) + } + if binlog != nil { + binlog.Log(&binarylog.ClientMessage{ + Message: d, + }) } if trInfo != nil { trInfo.tr.LazyLog(&payload{sent: false, msg: v}, true) @@ -1023,15 +978,25 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. if e := t.WriteStatus(stream, appStatus); e != nil { grpclog.Warningf("grpc: Server.processUnaryRPC failed to write status: %v", e) } + if binlog != nil { + if h, _ := stream.Header(); h.Len() > 0 { + // Only log serverHeader if there was header. Otherwise it can + // be trailer only. + binlog.Log(&binarylog.ServerHeader{ + Header: h, + }) + } + binlog.Log(&binarylog.ServerTrailer{ + Trailer: stream.Trailer(), + Err: appErr, + }) + } return appErr } if trInfo != nil { trInfo.tr.LazyLog(stringer("OK"), false) } - opts := &transport.Options{ - Last: true, - Delay: false, - } + opts := &transport.Options{Last: true} if err := s.sendResponse(t, stream, reply, cp, opts, comp); err != nil { if err == io.EOF { @@ -1046,16 +1011,31 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. switch st := err.(type) { case transport.ConnectionError: // Nothing to do here. - case transport.StreamError: - if e := t.WriteStatus(stream, status.New(st.Code, st.Desc)); e != nil { - grpclog.Warningf("grpc: Server.processUnaryRPC failed to write status %v", e) - } default: panic(fmt.Sprintf("grpc: Unexpected error (%T) from sendResponse: %v", st, st)) } } + if binlog != nil { + h, _ := stream.Header() + binlog.Log(&binarylog.ServerHeader{ + Header: h, + }) + binlog.Log(&binarylog.ServerTrailer{ + Trailer: stream.Trailer(), + Err: appErr, + }) + } return err } + if binlog != nil { + h, _ := stream.Header() + binlog.Log(&binarylog.ServerHeader{ + Header: h, + }) + binlog.Log(&binarylog.ServerMessage{ + Message: reply, + }) + } if channelz.IsOn() { t.IncrMsgSent() } @@ -1065,7 +1045,14 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. // TODO: Should we be logging if writing status failed here, like above? // Should the logging be in WriteStatus? Should we ignore the WriteStatus // error or allow the stats handler to see it? - return t.WriteStatus(stream, status.New(codes.OK, "")) + err = t.WriteStatus(stream, status.New(codes.OK, "")) + if binlog != nil { + binlog.Log(&binarylog.ServerTrailer{ + Trailer: stream.Trailer(), + Err: appErr, + }) + } + return err } func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transport.Stream, srv *service, sd *StreamDesc, trInfo *traceInfo) (err error) { @@ -1099,17 +1086,40 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp } ctx := NewContextWithServerTransportStream(stream.Context(), stream) ss := &serverStream{ - ctx: ctx, - t: t, - s: stream, - p: &parser{r: stream}, - codec: s.getCodec(stream.ContentSubtype()), + ctx: ctx, + t: t, + s: stream, + p: &parser{r: stream}, + codec: s.getCodec(stream.ContentSubtype()), maxReceiveMessageSize: s.opts.maxReceiveMessageSize, maxSendMessageSize: s.opts.maxSendMessageSize, trInfo: trInfo, statsHandler: sh, } + ss.binlog = binarylog.GetMethodLogger(stream.Method()) + if ss.binlog != nil { + md, _ := metadata.FromIncomingContext(ctx) + logEntry := &binarylog.ClientHeader{ + Header: md, + MethodName: stream.Method(), + PeerAddr: nil, + } + if deadline, ok := ctx.Deadline(); ok { + logEntry.Timeout = deadline.Sub(time.Now()) + if logEntry.Timeout < 0 { + logEntry.Timeout = 0 + } + } + if a := md[":authority"]; len(a) > 0 { + logEntry.Authority = a[0] + } + if peer, ok := peer.FromContext(ss.Context()); ok { + logEntry.PeerAddr = peer.Addr + } + ss.binlog.Log(logEntry) + } + // If dc is set and matches the stream's compression, use it. Otherwise, try // to find a matching registered compressor for decomp. if rc := stream.RecvCompress(); s.opts.dc != nil && s.opts.dc.Type() == rc { @@ -1169,12 +1179,7 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp if appErr != nil { appStatus, ok := status.FromError(appErr) if !ok { - switch err := appErr.(type) { - case transport.StreamError: - appStatus = status.New(err.Code, err.Desc) - default: - appStatus = status.New(codes.Unknown, appErr.Error()) - } + appStatus = status.New(codes.Unknown, appErr.Error()) appErr = appStatus.Err() } if trInfo != nil { @@ -1184,6 +1189,12 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp ss.mu.Unlock() } t.WriteStatus(ss.s, appStatus) + if ss.binlog != nil { + ss.binlog.Log(&binarylog.ServerTrailer{ + Trailer: ss.s.Trailer(), + Err: appErr, + }) + } // TODO: Should we log an error from WriteStatus here and below? return appErr } @@ -1192,7 +1203,14 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp ss.trInfo.tr.LazyLog(stringer("OK"), false) ss.mu.Unlock() } - return t.WriteStatus(ss.s, status.New(codes.OK, "")) + err = t.WriteStatus(ss.s, status.New(codes.OK, "")) + if ss.binlog != nil { + ss.binlog.Log(&binarylog.ServerTrailer{ + Trailer: ss.s.Trailer(), + Err: appErr, + }) + } + return err } func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Stream, trInfo *traceInfo) { @@ -1221,47 +1239,27 @@ func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Str } service := sm[:pos] method := sm[pos+1:] - srv, ok := s.m[service] - if !ok { - if unknownDesc := s.opts.unknownStreamDesc; unknownDesc != nil { - s.processStreamingRPC(t, stream, nil, unknownDesc, trInfo) + + if srv, ok := s.m[service]; ok { + if md, ok := srv.md[method]; ok { + s.processUnaryRPC(t, stream, srv, md, trInfo) return } - if trInfo != nil { - trInfo.tr.LazyLog(&fmtStringer{"Unknown service %v", []interface{}{service}}, true) - trInfo.tr.SetError() - } - errDesc := fmt.Sprintf("unknown service %v", service) - if err := t.WriteStatus(stream, status.New(codes.Unimplemented, errDesc)); err != nil { - if trInfo != nil { - trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true) - trInfo.tr.SetError() - } - grpclog.Warningf("grpc: Server.handleStream failed to write status: %v", err) - } - if trInfo != nil { - trInfo.tr.Finish() + if sd, ok := srv.sd[method]; ok { + s.processStreamingRPC(t, stream, srv, sd, trInfo) + return } - return - } - // Unary RPC or Streaming RPC? - if md, ok := srv.md[method]; ok { - s.processUnaryRPC(t, stream, srv, md, trInfo) - return } - if sd, ok := srv.sd[method]; ok { - s.processStreamingRPC(t, stream, srv, sd, trInfo) + // Unknown service, or known server unknown method. + if unknownDesc := s.opts.unknownStreamDesc; unknownDesc != nil { + s.processStreamingRPC(t, stream, nil, unknownDesc, trInfo) return } if trInfo != nil { - trInfo.tr.LazyLog(&fmtStringer{"Unknown method %v", []interface{}{method}}, true) + trInfo.tr.LazyLog(&fmtStringer{"Unknown service %v", []interface{}{service}}, true) trInfo.tr.SetError() } - if unknownDesc := s.opts.unknownStreamDesc; unknownDesc != nil { - s.processStreamingRPC(t, stream, nil, unknownDesc, trInfo) - return - } - errDesc := fmt.Sprintf("unknown method %v", method) + errDesc := fmt.Sprintf("unknown service %v", service) if err := t.WriteStatus(stream, status.New(codes.Unimplemented, errDesc)); err != nil { if trInfo != nil { trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true) @@ -1410,12 +1408,6 @@ func (s *Server) GracefulStop() { s.mu.Unlock() } -func init() { - internal.TestingUseHandlerImpl = func(arg interface{}) { - arg.(*Server).opts.useHandlerImpl = true - } -} - // contentSubtype must be lowercase // cannot return nil func (s *Server) getCodec(contentSubtype string) baseCodec { @@ -1484,3 +1476,11 @@ func Method(ctx context.Context) (string, bool) { } return s.Method(), true } + +type channelzServer struct { + s *Server +} + +func (c *channelzServer) ChannelzMetric() *channelz.ServerInternalMetric { + return c.s.channelzMetric() +} diff --git a/vendor/google.golang.org/grpc/server_test.go b/vendor/google.golang.org/grpc/server_test.go index 77e40b02997787e0dbbaded704a997fb3625976c..125be01c57b2aeeca2f1ee485bbec02b3789c9ac 100644 --- a/vendor/google.golang.org/grpc/server_test.go +++ b/vendor/google.golang.org/grpc/server_test.go @@ -19,15 +19,15 @@ package grpc import ( + "context" "net" "reflect" "strings" "testing" "time" - "golang.org/x/net/context" "google.golang.org/grpc/internal/leakcheck" - "google.golang.org/grpc/transport" + "google.golang.org/grpc/internal/transport" ) type emptyServiceServer interface{} diff --git a/vendor/google.golang.org/grpc/service_config.go b/vendor/google.golang.org/grpc/service_config.go index 015631d8d38a8b371eaba9f96657b14a4f5e1b96..162857e204d55e987e70c77acfab9f03f7117981 100644 --- a/vendor/google.golang.org/grpc/service_config.go +++ b/vendor/google.golang.org/grpc/service_config.go @@ -25,6 +25,7 @@ import ( "strings" "time" + "google.golang.org/grpc/codes" "google.golang.org/grpc/grpclog" ) @@ -56,6 +57,8 @@ type MethodConfig struct { // MaxRespSize is the maximum allowed payload size for an individual response in a // stream (server->client) in bytes. MaxRespSize *int + // RetryPolicy configures retry options for the method. + retryPolicy *retryPolicy } // ServiceConfig is provided by the service provider and contains parameters for how @@ -68,13 +71,93 @@ type ServiceConfig struct { // LB is the load balancer the service providers recommends. The balancer specified // via grpc.WithBalancer will override this. LB *string - // Methods contains a map for the methods in this service. - // If there is an exact match for a method (i.e. /service/method) in the map, use the corresponding MethodConfig. - // If there's no exact match, look for the default config for the service (/service/) and use the corresponding MethodConfig if it exists. - // Otherwise, the method has no MethodConfig to use. + + // Methods contains a map for the methods in this service. If there is an + // exact match for a method (i.e. /service/method) in the map, use the + // corresponding MethodConfig. If there's no exact match, look for the + // default config for the service (/service/) and use the corresponding + // MethodConfig if it exists. Otherwise, the method has no MethodConfig to + // use. Methods map[string]MethodConfig - stickinessMetadataKey *string + // If a retryThrottlingPolicy is provided, gRPC will automatically throttle + // retry attempts and hedged RPCs when the client’s ratio of failures to + // successes exceeds a threshold. + // + // For each server name, the gRPC client will maintain a token_count which is + // initially set to maxTokens, and can take values between 0 and maxTokens. + // + // Every outgoing RPC (regardless of service or method invoked) will change + // token_count as follows: + // + // - Every failed RPC will decrement the token_count by 1. + // - Every successful RPC will increment the token_count by tokenRatio. + // + // If token_count is less than or equal to maxTokens / 2, then RPCs will not + // be retried and hedged RPCs will not be sent. + retryThrottling *retryThrottlingPolicy + // healthCheckConfig must be set as one of the requirement to enable LB channel + // health check. + healthCheckConfig *healthCheckConfig +} + +// healthCheckConfig defines the go-native version of the LB channel health check config. +type healthCheckConfig struct { + // serviceName is the service name to use in the health-checking request. + ServiceName string +} + +// retryPolicy defines the go-native version of the retry policy defined by the +// service config here: +// https://github.com/grpc/proposal/blob/master/A6-client-retries.md#integration-with-service-config +type retryPolicy struct { + // MaxAttempts is the maximum number of attempts, including the original RPC. + // + // This field is required and must be two or greater. + maxAttempts int + + // Exponential backoff parameters. The initial retry attempt will occur at + // random(0, initialBackoffMS). In general, the nth attempt will occur at + // random(0, + // min(initialBackoffMS*backoffMultiplier**(n-1), maxBackoffMS)). + // + // These fields are required and must be greater than zero. + initialBackoff time.Duration + maxBackoff time.Duration + backoffMultiplier float64 + + // The set of status codes which may be retried. + // + // Status codes are specified as strings, e.g., "UNAVAILABLE". + // + // This field is required and must be non-empty. + // Note: a set is used to store this for easy lookup. + retryableStatusCodes map[codes.Code]bool +} + +type jsonRetryPolicy struct { + MaxAttempts int + InitialBackoff string + MaxBackoff string + BackoffMultiplier float64 + RetryableStatusCodes []codes.Code +} + +// retryThrottlingPolicy defines the go-native version of the retry throttling +// policy defined by the service config here: +// https://github.com/grpc/proposal/blob/master/A6-client-retries.md#integration-with-service-config +type retryThrottlingPolicy struct { + // The number of tokens starts at maxTokens. The token_count will always be + // between 0 and maxTokens. + // + // This field is required and must be greater than zero. + MaxTokens float64 + // The amount of tokens to add on each successful RPC. Typically this will + // be some number between 0 and 1, e.g., 0.1. + // + // This field is required and must be greater than zero. Up to 3 decimal + // places are supported. + TokenRatio float64 } func parseDuration(s *string) (*time.Duration, error) { @@ -144,16 +227,21 @@ type jsonMC struct { Timeout *string MaxRequestMessageBytes *int64 MaxResponseMessageBytes *int64 + RetryPolicy *jsonRetryPolicy } // TODO(lyuxuan): delete this struct after cleaning up old service config implementation. type jsonSC struct { - LoadBalancingPolicy *string - StickinessMetadataKey *string - MethodConfig *[]jsonMC + LoadBalancingPolicy *string + MethodConfig *[]jsonMC + RetryThrottling *retryThrottlingPolicy + HealthCheckConfig *healthCheckConfig } func parseServiceConfig(js string) (ServiceConfig, error) { + if len(js) == 0 { + return ServiceConfig{}, fmt.Errorf("no JSON service config provided") + } var rsc jsonSC err := json.Unmarshal([]byte(js), &rsc) if err != nil { @@ -161,10 +249,10 @@ func parseServiceConfig(js string) (ServiceConfig, error) { return ServiceConfig{}, err } sc := ServiceConfig{ - LB: rsc.LoadBalancingPolicy, - Methods: make(map[string]MethodConfig), - - stickinessMetadataKey: rsc.StickinessMetadataKey, + LB: rsc.LoadBalancingPolicy, + Methods: make(map[string]MethodConfig), + retryThrottling: rsc.RetryThrottling, + healthCheckConfig: rsc.HealthCheckConfig, } if rsc.MethodConfig == nil { return sc, nil @@ -184,6 +272,10 @@ func parseServiceConfig(js string) (ServiceConfig, error) { WaitForReady: m.WaitForReady, Timeout: d, } + if mc.retryPolicy, err = convertRetryPolicy(m.RetryPolicy); err != nil { + grpclog.Warningf("grpc: parseServiceConfig error unmarshaling %s due to %v", js, err) + return ServiceConfig{}, err + } if m.MaxRequestMessageBytes != nil { if *m.MaxRequestMessageBytes > int64(maxInt) { mc.MaxReqSize = newInt(maxInt) @@ -205,9 +297,56 @@ func parseServiceConfig(js string) (ServiceConfig, error) { } } + if sc.retryThrottling != nil { + if sc.retryThrottling.MaxTokens <= 0 || + sc.retryThrottling.MaxTokens >= 1000 || + sc.retryThrottling.TokenRatio <= 0 { + // Illegal throttling config; disable throttling. + sc.retryThrottling = nil + } + } return sc, nil } +func convertRetryPolicy(jrp *jsonRetryPolicy) (p *retryPolicy, err error) { + if jrp == nil { + return nil, nil + } + ib, err := parseDuration(&jrp.InitialBackoff) + if err != nil { + return nil, err + } + mb, err := parseDuration(&jrp.MaxBackoff) + if err != nil { + return nil, err + } + + if jrp.MaxAttempts <= 1 || + *ib <= 0 || + *mb <= 0 || + jrp.BackoffMultiplier <= 0 || + len(jrp.RetryableStatusCodes) == 0 { + grpclog.Warningf("grpc: ignoring retry policy %v due to illegal configuration", jrp) + return nil, nil + } + + rp := &retryPolicy{ + maxAttempts: jrp.MaxAttempts, + initialBackoff: *ib, + maxBackoff: *mb, + backoffMultiplier: jrp.BackoffMultiplier, + retryableStatusCodes: make(map[codes.Code]bool), + } + if rp.maxAttempts > 5 { + // TODO(retry): Make the max maxAttempts configurable. + rp.maxAttempts = 5 + } + for _, code := range jrp.RetryableStatusCodes { + rp.retryableStatusCodes[code] = true + } + return rp, nil +} + func min(a, b *int) *int { if *a < *b { return a diff --git a/vendor/google.golang.org/grpc/stats/handlers.go b/vendor/google.golang.org/grpc/stats/handlers.go index 05b384c693186bed385b2bcda0028cf7c145e902..dc03731e45efa051eabb48ac4c1837a3e2a80e9f 100644 --- a/vendor/google.golang.org/grpc/stats/handlers.go +++ b/vendor/google.golang.org/grpc/stats/handlers.go @@ -19,9 +19,8 @@ package stats import ( + "context" "net" - - "golang.org/x/net/context" ) // ConnTagInfo defines the relevant information needed by connection context tagger. diff --git a/vendor/google.golang.org/grpc/stats/stats.go b/vendor/google.golang.org/grpc/stats/stats.go index 3f13190a0ac6c03a87960a2d35b72d1516b142a9..84f77dafa58cdc4cbb52cacba0c3e70200509491 100644 --- a/vendor/google.golang.org/grpc/stats/stats.go +++ b/vendor/google.golang.org/grpc/stats/stats.go @@ -24,10 +24,9 @@ package stats // import "google.golang.org/grpc/stats" import ( + "context" "net" "time" - - "golang.org/x/net/context" ) // RPCStats contains stats information about RPCs. diff --git a/vendor/google.golang.org/grpc/stats/stats_test.go b/vendor/google.golang.org/grpc/stats/stats_test.go index 00a5e4f31b827e50cdb56c4b6d63281f8b7d52c2..008d684c1022a4da26db2323deb9a442d9b485dd 100644 --- a/vendor/google.golang.org/grpc/stats/stats_test.go +++ b/vendor/google.golang.org/grpc/stats/stats_test.go @@ -1,5 +1,3 @@ -// +build go1.7 - /* * * Copyright 2016 gRPC authors. @@ -21,6 +19,7 @@ package stats_test import ( + "context" "fmt" "io" "net" @@ -30,7 +29,6 @@ import ( "time" "github.com/golang/protobuf/proto" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/grpc/stats" @@ -403,7 +401,7 @@ const ( inTrailer outPayload outHeader - outTrailer + // TODO: test outTrailer ? connbegin connend ) diff --git a/vendor/google.golang.org/grpc/status/go16.go b/vendor/google.golang.org/grpc/status/go16.go deleted file mode 100644 index e59b53e82be7159866daee4a841e1dd152634a9b..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/status/go16.go +++ /dev/null @@ -1,42 +0,0 @@ -// +build go1.6,!go1.7 - -/* - * - * Copyright 2018 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package status - -import ( - "golang.org/x/net/context" - "google.golang.org/grpc/codes" -) - -// FromContextError converts a context error into a Status. It returns a -// Status with codes.OK if err is nil, or a Status with codes.Unknown if err is -// non-nil and not a context error. -func FromContextError(err error) *Status { - switch err { - case nil: - return New(codes.OK, "") - case context.DeadlineExceeded: - return New(codes.DeadlineExceeded, err.Error()) - case context.Canceled: - return New(codes.Canceled, err.Error()) - default: - return New(codes.Unknown, err.Error()) - } -} diff --git a/vendor/google.golang.org/grpc/status/go17.go b/vendor/google.golang.org/grpc/status/go17.go deleted file mode 100644 index 090215149cfb5a9cc8f312e724374fd1ab45df9e..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/status/go17.go +++ /dev/null @@ -1,44 +0,0 @@ -// +build go1.7 - -/* - * - * Copyright 2018 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package status - -import ( - "context" - - netctx "golang.org/x/net/context" - "google.golang.org/grpc/codes" -) - -// FromContextError converts a context error into a Status. It returns a -// Status with codes.OK if err is nil, or a Status with codes.Unknown if err is -// non-nil and not a context error. -func FromContextError(err error) *Status { - switch err { - case nil: - return New(codes.OK, "") - case context.DeadlineExceeded, netctx.DeadlineExceeded: - return New(codes.DeadlineExceeded, err.Error()) - case context.Canceled, netctx.Canceled: - return New(codes.Canceled, err.Error()) - default: - return New(codes.Unknown, err.Error()) - } -} diff --git a/vendor/google.golang.org/grpc/status/status.go b/vendor/google.golang.org/grpc/status/status.go index 9c61b094508fe02ac43349dd31e9d349ea1fa00c..ed36681bb54658291ad3e23a48ddd163aacb5c9f 100644 --- a/vendor/google.golang.org/grpc/status/status.go +++ b/vendor/google.golang.org/grpc/status/status.go @@ -28,6 +28,7 @@ package status import ( + "context" "errors" "fmt" @@ -126,7 +127,9 @@ func FromError(err error) (s *Status, ok bool) { if err == nil { return &Status{s: &spb.Status{Code: int32(codes.OK)}}, true } - if se, ok := err.(interface{ GRPCStatus() *Status }); ok { + if se, ok := err.(interface { + GRPCStatus() *Status + }); ok { return se.GRPCStatus(), true } return New(codes.Unknown, err.Error()), false @@ -182,8 +185,26 @@ func Code(err error) codes.Code { if err == nil { return codes.OK } - if se, ok := err.(interface{ GRPCStatus() *Status }); ok { + if se, ok := err.(interface { + GRPCStatus() *Status + }); ok { return se.GRPCStatus().Code() } return codes.Unknown } + +// FromContextError converts a context error into a Status. It returns a +// Status with codes.OK if err is nil, or a Status with codes.Unknown if err is +// non-nil and not a context error. +func FromContextError(err error) *Status { + switch err { + case nil: + return New(codes.OK, "") + case context.DeadlineExceeded: + return New(codes.DeadlineExceeded, err.Error()) + case context.Canceled: + return New(codes.Canceled, err.Error()) + default: + return New(codes.Unknown, err.Error()) + } +} diff --git a/vendor/google.golang.org/grpc/status/status_test.go b/vendor/google.golang.org/grpc/status/status_test.go index 1eb1320932099ebfb214aa0c690ddca743facfbd..011cb0aead737126f5eaf8a042e1892fd8101fff 100644 --- a/vendor/google.golang.org/grpc/status/status_test.go +++ b/vendor/google.golang.org/grpc/status/status_test.go @@ -19,6 +19,7 @@ package status import ( + "context" "errors" "fmt" "reflect" @@ -28,7 +29,6 @@ import ( "github.com/golang/protobuf/ptypes" apb "github.com/golang/protobuf/ptypes/any" dpb "github.com/golang/protobuf/ptypes/duration" - "golang.org/x/net/context" cpb "google.golang.org/genproto/googleapis/rpc/code" epb "google.golang.org/genproto/googleapis/rpc/errdetails" spb "google.golang.org/genproto/googleapis/rpc/status" diff --git a/vendor/google.golang.org/grpc/stickiness_linkedmap.go b/vendor/google.golang.org/grpc/stickiness_linkedmap.go deleted file mode 100644 index 1c726af1640d5d5aa4a58c106c8709c363a95ac1..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/stickiness_linkedmap.go +++ /dev/null @@ -1,97 +0,0 @@ -/* - * - * Copyright 2018 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package grpc - -import ( - "container/list" -) - -type linkedMapKVPair struct { - key string - value *stickyStoreEntry -} - -// linkedMap is an implementation of a map that supports removing the oldest -// entry. -// -// linkedMap is NOT thread safe. -// -// It's for use of stickiness only! -type linkedMap struct { - m map[string]*list.Element - l *list.List // Head of the list is the oldest element. -} - -// newLinkedMap returns a new LinkedMap. -func newLinkedMap() *linkedMap { - return &linkedMap{ - m: make(map[string]*list.Element), - l: list.New(), - } -} - -// put adds entry (key, value) to the map. Existing key will be overridden. -func (m *linkedMap) put(key string, value *stickyStoreEntry) { - if oldE, ok := m.m[key]; ok { - // Remove existing entry. - m.l.Remove(oldE) - } - e := m.l.PushBack(&linkedMapKVPair{key: key, value: value}) - m.m[key] = e -} - -// get returns the value of the given key. -func (m *linkedMap) get(key string) (*stickyStoreEntry, bool) { - e, ok := m.m[key] - if !ok { - return nil, false - } - m.l.MoveToBack(e) - return e.Value.(*linkedMapKVPair).value, true -} - -// remove removes key from the map, and returns the value. The map is not -// modified if key is not in the map. -func (m *linkedMap) remove(key string) (*stickyStoreEntry, bool) { - e, ok := m.m[key] - if !ok { - return nil, false - } - delete(m.m, key) - m.l.Remove(e) - return e.Value.(*linkedMapKVPair).value, true -} - -// len returns the len of the map. -func (m *linkedMap) len() int { - return len(m.m) -} - -// clear removes all elements from the map. -func (m *linkedMap) clear() { - m.m = make(map[string]*list.Element) - m.l = list.New() -} - -// removeOldest removes the oldest key from the map. -func (m *linkedMap) removeOldest() { - e := m.l.Front() - m.l.Remove(e) - delete(m.m, e.Value.(*linkedMapKVPair).key) -} diff --git a/vendor/google.golang.org/grpc/stickiness_linkedmap_test.go b/vendor/google.golang.org/grpc/stickiness_linkedmap_test.go deleted file mode 100644 index e2d763555ca7d06dd5812a6a88f67e8cbf217b69..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/stickiness_linkedmap_test.go +++ /dev/null @@ -1,186 +0,0 @@ -/* - * - * Copyright 2018 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package grpc - -import ( - "container/list" - "fmt" - "reflect" - "testing" -) - -var linkedMapTestData = make([]*stickyStoreEntry, 5) - -func TestLinkedMapPutGet(t *testing.T) { - m := newLinkedMap() - m.put("one", linkedMapTestData[0]) - if got, ok := m.get("one"); !ok || got != linkedMapTestData[0] { - t.Errorf("m.Get(%v) = %v, %v, want %v, true", 1, got, ok, "one") - } - m.put("two", linkedMapTestData[1]) - if got, ok := m.get("two"); !ok || got != linkedMapTestData[1] { - t.Errorf("m.Get(%v) = %v, %v, want %v, true", 2, got, ok, "two") - } - m.put("oneone", linkedMapTestData[4]) - if got, ok := m.get("one"); !ok || got != linkedMapTestData[4] { - t.Errorf("m.Get(%v) = %v, %v, want %v, true", 1, got, ok, "oneone") - } -} - -func TestLinkedMapRemove(t *testing.T) { - m := newLinkedMap() - m.put("one", linkedMapTestData[0]) - if got, ok := m.get("one"); !ok || got != linkedMapTestData[0] { - t.Errorf("m.Get(%v) = %v, %v, want %v, true", 1, got, ok, "one") - } - m.put("two", linkedMapTestData[1]) - if got, ok := m.get("two"); !ok || got != linkedMapTestData[1] { - t.Errorf("m.Get(%v) = %v, %v, want %v, true", 2, got, ok, "two") - } - - if got, ok := m.remove("one"); !ok || got != linkedMapTestData[0] { - t.Errorf("m.Remove(%v) = %v, %v, want %v, true", 1, got, ok, "one") - } - if got, ok := m.get("one"); ok { - t.Errorf("m.Get(%v) = %v, %v, want _, false", 1, got, ok) - } - // 2 should still in the map. - if got, ok := m.get("two"); !ok || got != linkedMapTestData[1] { - t.Errorf("m.Get(%v) = %v, %v, want %v, true", 2, got, ok, "two") - } -} - -func TestLinkedMapLen(t *testing.T) { - m := newLinkedMap() - if got := m.len(); got != 0 { - t.Errorf("m.Len() = %v, want %v", got, 0) - } - m.put("one", linkedMapTestData[0]) - if got := m.len(); got != 1 { - t.Errorf("m.Len() = %v, want %v", got, 1) - } - m.put("two", linkedMapTestData[1]) - if got := m.len(); got != 2 { - t.Errorf("m.Len() = %v, want %v", got, 2) - } - m.put("one", linkedMapTestData[4]) - if got := m.len(); got != 2 { - t.Errorf("m.Len() = %v, want %v", got, 2) - } - - // Internal checks. - if got := len(m.m); got != 2 { - t.Errorf("len(m.m) = %v, want %v", got, 2) - } - if got := m.l.Len(); got != 2 { - t.Errorf("m.l.Len() = %v, want %v", got, 2) - } -} - -func TestLinkedMapClear(t *testing.T) { - m := newLinkedMap() - m.put("one", linkedMapTestData[0]) - if got, ok := m.get("one"); !ok || got != linkedMapTestData[0] { - t.Errorf("m.Get(%v) = %v, %v, want %v, true", 1, got, ok, "one") - } - m.put("two", linkedMapTestData[1]) - if got, ok := m.get("two"); !ok || got != linkedMapTestData[1] { - t.Errorf("m.Get(%v) = %v, %v, want %v, true", 2, got, ok, "two") - } - - m.clear() - if got, ok := m.get("one"); ok { - t.Errorf("m.Get(%v) = %v, %v, want _, false", 1, got, ok) - } - if got, ok := m.get("two"); ok { - t.Errorf("m.Get(%v) = %v, %v, want _, false", 2, got, ok) - } - if got := m.len(); got != 0 { - t.Errorf("m.Len() = %v, want %v", got, 0) - } -} - -func TestLinkedMapRemoveOldest(t *testing.T) { - m := newLinkedMap() - m.put("one", linkedMapTestData[0]) - m.put("two", linkedMapTestData[1]) - m.put("three", linkedMapTestData[2]) - m.put("four", linkedMapTestData[3]) - if got, ok := m.get("one"); !ok || got != linkedMapTestData[0] { - t.Errorf("m.Get(%v) = %v, %v, want %v, true", 1, got, ok, "one") - } - if got, ok := m.get("two"); !ok || got != linkedMapTestData[1] { - t.Errorf("m.Get(%v) = %v, %v, want %v, true", 2, got, ok, "two") - } - if got, ok := m.get("three"); !ok || got != linkedMapTestData[2] { - t.Errorf("m.Get(%v) = %v, %v, want %v, true", 3, got, ok, "three") - } - if got, ok := m.get("four"); !ok || got != linkedMapTestData[3] { - t.Errorf("m.Get(%v) = %v, %v, want %v, true", 4, got, ok, "four") - } - - if err := checkListOrdered(m.l, []string{"one", "two", "three", "four"}); err != nil { - t.Fatalf("m.l is not expected: %v", err) - } - - m.put("three", linkedMapTestData[2]) - if err := checkListOrdered(m.l, []string{"one", "two", "four", "three"}); err != nil { - t.Fatalf("m.l is not expected: %v", err) - } - m.put("four", linkedMapTestData[3]) - if err := checkListOrdered(m.l, []string{"one", "two", "three", "four"}); err != nil { - t.Fatalf("m.l is not expected: %v", err) - } - - m.removeOldest() - if got, ok := m.get("one"); ok { - t.Errorf("m.Get(%v) = %v, %v, want _, false", 1, got, ok) - } - if err := checkListOrdered(m.l, []string{"two", "three", "four"}); err != nil { - t.Fatalf("m.l is not expected: %v", err) - } - - m.get("two") // 2 is refreshed, 3 becomes the oldest - if err := checkListOrdered(m.l, []string{"three", "four", "two"}); err != nil { - t.Fatalf("m.l is not expected: %v", err) - } - - m.removeOldest() - if got, ok := m.get("three"); ok { - t.Errorf("m.Get(%v) = %v, %v, want _, false", 3, got, ok) - } - // 2 and 4 are still in map. - if got, ok := m.get("two"); !ok || got != linkedMapTestData[1] { - t.Errorf("m.Get(%v) = %v, %v, want %v, true", 2, got, ok, "two") - } - if got, ok := m.get("four"); !ok || got != linkedMapTestData[3] { - t.Errorf("m.Get(%v) = %v, %v, want %v, true", 4, got, ok, "four") - } -} - -func checkListOrdered(l *list.List, want []string) error { - got := make([]string, 0, len(want)) - for p := l.Front(); p != nil; p = p.Next() { - got = append(got, p.Value.(*linkedMapKVPair).key) - } - if !reflect.DeepEqual(got, want) { - return fmt.Errorf("list elements: %v, want %v", got, want) - } - return nil -} diff --git a/vendor/google.golang.org/grpc/stickiness_test.go b/vendor/google.golang.org/grpc/stickiness_test.go deleted file mode 100644 index f625d680bcf5618dc32f10af5eba24a048a6561f..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/stickiness_test.go +++ /dev/null @@ -1,288 +0,0 @@ -/* - * - * Copyright 2018 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package grpc - -import ( - "fmt" - "math" - "strings" - "testing" - "time" - - "golang.org/x/net/context" - "google.golang.org/grpc/balancer/roundrobin" - "google.golang.org/grpc/internal/leakcheck" - "google.golang.org/grpc/metadata" - "google.golang.org/grpc/resolver" - "google.golang.org/grpc/resolver/manual" -) - -func TestStickyKeyFromContext(t *testing.T) { - for _, test := range []struct { - org, add []string - mdKey string - wantStr string - wantBool bool - }{ - {[]string{}, []string{}, "", "", false}, - {[]string{"k1", "v1"}, []string{"k2", "v2"}, "k", "", false}, - - {[]string{"k", "v"}, []string{}, "k", "v", true}, - {[]string{}, []string{"k", "v"}, "k", "v", true}, - {[]string{"k1", "v1"}, []string{"k2", "v2"}, "k1", "v1", true}, - {[]string{"k1", "v1"}, []string{"k2", "v2"}, "k2", "v2", true}, - } { - ctx := context.Background() - if len(test.org) > 0 { - ctx = metadata.NewOutgoingContext(ctx, metadata.Pairs(test.org...)) - } - if len(test.add) > 0 { - ctx = metadata.AppendToOutgoingContext(ctx, test.add...) - } - got, ok := stickyKeyFromContext(ctx, test.mdKey) - if got != test.wantStr || ok != test.wantBool { - t.Errorf("test: %+v, got: %q, %v, want: %q, %v\n", test, got, ok, test.wantStr, test.wantBool) - } - } -} - -func TestStickinessServiceConfig(t *testing.T) { - envConfigStickinessOn = true - defer func() { envConfigStickinessOn = false }() - defer leakcheck.Check(t) - r, rcleanup := manual.GenerateAndRegisterManualResolver() - defer rcleanup() - - cc, err := Dial(r.Scheme()+":///test.server", WithInsecure()) - if err != nil { - t.Fatalf("failed to dial: %v", err) - } - defer cc.Close() - - const testInput = "testStickinessKey" - wantStr := strings.ToLower(testInput) - - r.NewServiceConfig(fmt.Sprintf(`{"stickinessMetadataKey": "%v"}`, testInput)) // ToLower() will be applied to the input. - - for i := 0; i < 1000; i++ { - if key := cc.blockingpicker.getStickinessMDKey(); key == wantStr { - return - } - time.Sleep(time.Millisecond) - } - t.Fatalf("cc.blockingpicker.stickiness.stickinessMDKey failed to change to %v within one second", wantStr) -} - -func TestStickinessEnd2end(t *testing.T) { - envConfigStickinessOn = true - defer func() { envConfigStickinessOn = false }() - defer leakcheck.Check(t) - r, rcleanup := manual.GenerateAndRegisterManualResolver() - defer rcleanup() - - numServers := 2 - servers, _, scleanup := startServers(t, numServers, math.MaxInt32) - defer scleanup() - - cc, err := Dial(r.Scheme()+":///test.server", - WithInsecure(), WithCodec(testCodec{}), WithBalancerName(roundrobin.Name)) - if err != nil { - t.Fatalf("failed to dial: %v", err) - } - defer cc.Close() - req := "port" - var reply string - r.NewAddress([]resolver.Address{{Addr: servers[0].addr}, {Addr: servers[1].addr}}) - - var ( - i int - picked []int - ) - - // Check that each backend will be picked for at least 3 times. - picked = make([]int, 2, 2) - for i = 0; i < 1000; i++ { - if err = Invoke(context.Background(), "/foo/bar", &req, &reply, cc); err != nil { - if errorDesc(err) == servers[0].port { - picked[0]++ - } else if errorDesc(err) == servers[1].port { - picked[1]++ - } - } - if picked[0] >= 3 && picked[1] >= 3 { - break - } - time.Sleep(time.Millisecond) - } - if i >= 1000 { - t.Fatalf("When doing roundrobin, addr1 was picked %v times, addr2 was picked %v times", picked[0], picked[1]) - } - - r.NewServiceConfig(fmt.Sprintf(`{"stickinessMetadataKey": "sessionid"}`)) - - // Should still be roundrobin. - picked = make([]int, 2, 2) - for i = 0; i < 1000; i++ { - if err = Invoke(context.Background(), "/foo/bar", &req, &reply, cc); err != nil { - if errorDesc(err) == servers[0].port { - picked[0]++ - } else if errorDesc(err) == servers[1].port { - picked[1]++ - } - } - if picked[0] >= 3 && picked[1] >= 3 { - break - } - time.Sleep(time.Millisecond) - } - if i >= 1000 { - t.Fatalf("When doing roundrobin, addr1 was picked %v times, addr2 was picked %v times", picked[0], picked[1]) - } - - // Do sticky call, only one backend will be picked. - picked = make([]int, 2, 2) - for i = 0; i < 100; i++ { - ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs("sessionid", "1")) - if err = Invoke(ctx, "/foo/bar", &req, &reply, cc); err != nil { - if errorDesc(err) == servers[0].port { - picked[0]++ - } else if errorDesc(err) == servers[1].port { - picked[1]++ - } - } - time.Sleep(time.Millisecond) - } - - if (picked[0] != 0) == (picked[1] != 0) { - t.Fatalf("When doing sticky RPC, addr1 was picked %v times, addr2 was picked %v times, want at least one of them to be 0", picked[0], picked[1]) - } - -} - -// Changing stickinessMDKey in service config will clear the sticky map. -func TestStickinessChangeMDKey(t *testing.T) { - envConfigStickinessOn = true - defer func() { envConfigStickinessOn = false }() - defer leakcheck.Check(t) - r, rcleanup := manual.GenerateAndRegisterManualResolver() - defer rcleanup() - - numServers := 2 - servers, _, scleanup := startServers(t, numServers, math.MaxInt32) - defer scleanup() - - cc, err := Dial(r.Scheme()+":///test.server", WithInsecure(), WithCodec(testCodec{})) - if err != nil { - t.Fatalf("failed to dial: %v", err) - } - defer cc.Close() - req := "port" - var reply string - r.NewAddress([]resolver.Address{{Addr: servers[0].addr}, {Addr: servers[1].addr}}) - - r.NewServiceConfig(fmt.Sprintf(`{"stickinessMetadataKey": "sessionid"}`)) - - // Do sticky call, only one backend will be picked, and there will be one - // entry in stickiness map. - for i := 0; i < 100; i++ { - ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs("sessionid", "1")) - Invoke(ctx, "/foo/bar", &req, &reply, cc) - time.Sleep(time.Millisecond) - } - - cc.blockingpicker.stickiness.mu.Lock() - mapLen := cc.blockingpicker.stickiness.store.len() - cc.blockingpicker.stickiness.mu.Unlock() - if mapLen != 1 { - t.Fatalf("length of stickiness map is %v, want 1", mapLen) - } - - r.NewServiceConfig(fmt.Sprintf(`{"stickinessMetadataKey": "sessionidnew"}`)) - - var i int - for i = 0; i < 1000; i++ { - cc.blockingpicker.stickiness.mu.Lock() - mapLen = cc.blockingpicker.stickiness.store.len() - cc.blockingpicker.stickiness.mu.Unlock() - if mapLen == 0 { - break - } - time.Sleep(time.Millisecond) - } - if i >= 1000 { - t.Fatalf("After 1 second, length of stickiness map is %v, want 0", mapLen) - } -} - -// Switching balancer will clear the sticky map. -func TestStickinessSwitchingBalancer(t *testing.T) { - envConfigStickinessOn = true - defer func() { envConfigStickinessOn = false }() - defer leakcheck.Check(t) - r, rcleanup := manual.GenerateAndRegisterManualResolver() - defer rcleanup() - - numServers := 2 - servers, _, scleanup := startServers(t, numServers, math.MaxInt32) - defer scleanup() - - cc, err := Dial(r.Scheme()+":///test.server", WithInsecure(), WithCodec(testCodec{})) - if err != nil { - t.Fatalf("failed to dial: %v", err) - } - defer cc.Close() - req := "port" - var reply string - r.NewAddress([]resolver.Address{{Addr: servers[0].addr}, {Addr: servers[1].addr}}) - - r.NewServiceConfig(fmt.Sprintf(`{"stickinessMetadataKey": "sessionid"}`)) - - // Do sticky call, only one backend will be picked, and there will be one - // entry in stickiness map. - for i := 0; i < 100; i++ { - ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs("sessionid", "1")) - Invoke(ctx, "/foo/bar", &req, &reply, cc) - time.Sleep(time.Millisecond) - } - - cc.blockingpicker.stickiness.mu.Lock() - mapLen := cc.blockingpicker.stickiness.store.len() - cc.blockingpicker.stickiness.mu.Unlock() - if mapLen != 1 { - t.Fatalf("length of stickiness map is %v, want 1", mapLen) - } - - cc.mu.Lock() - cc.switchBalancer("round_robin") - cc.mu.Unlock() - - var i int - for i = 0; i < 1000; i++ { - cc.blockingpicker.stickiness.mu.Lock() - mapLen = cc.blockingpicker.stickiness.store.len() - cc.blockingpicker.stickiness.mu.Unlock() - if mapLen == 0 { - break - } - time.Sleep(time.Millisecond) - } - if i >= 1000 { - t.Fatalf("After 1 second, length of stickiness map is %v, want 0", mapLen) - } -} diff --git a/vendor/google.golang.org/grpc/stream.go b/vendor/google.golang.org/grpc/stream.go index 152d9eccd62d37277a6e82b31201be790da23f41..0c266d6f9a342736a28b5af4281b01cf11a72edb 100644 --- a/vendor/google.golang.org/grpc/stream.go +++ b/vendor/google.golang.org/grpc/stream.go @@ -19,21 +19,28 @@ package grpc import ( + "context" "errors" "io" + "math" + "strconv" "sync" "time" - "golang.org/x/net/context" "golang.org/x/net/trace" "google.golang.org/grpc/balancer" "google.golang.org/grpc/codes" + "google.golang.org/grpc/connectivity" "google.golang.org/grpc/encoding" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/internal/binarylog" "google.golang.org/grpc/internal/channelz" + "google.golang.org/grpc/internal/grpcrand" + "google.golang.org/grpc/internal/transport" "google.golang.org/grpc/metadata" + "google.golang.org/grpc/peer" "google.golang.org/grpc/stats" "google.golang.org/grpc/status" - "google.golang.org/grpc/transport" ) // StreamHandler defines the handler called by gRPC server to complete the @@ -55,31 +62,20 @@ type StreamDesc struct { // Stream defines the common interface a client or server stream has to satisfy. // -// All errors returned from Stream are compatible with the status package. +// Deprecated: See ClientStream and ServerStream documentation instead. type Stream interface { - // Context returns the context for this stream. + // Deprecated: See ClientStream and ServerStream documentation instead. Context() context.Context - // SendMsg blocks until it sends m, the stream is done or the stream - // breaks. - // On error, it aborts the stream and returns an RPC status on client - // side. On server side, it simply returns the error to the caller. - // SendMsg is called by generated code. Also Users can call SendMsg - // directly when it is really needed in their use cases. - // It's safe to have a goroutine calling SendMsg and another goroutine calling - // recvMsg on the same stream at the same time. - // But it is not safe to call SendMsg on the same stream in different goroutines. + // Deprecated: See ClientStream and ServerStream documentation instead. SendMsg(m interface{}) error - // RecvMsg blocks until it receives a message or the stream is - // done. On client side, it returns io.EOF when the stream is done. On - // any other error, it aborts the stream and returns an RPC status. On - // server side, it simply returns the error to the caller. - // It's safe to have a goroutine calling SendMsg and another goroutine calling - // recvMsg on the same stream at the same time. - // But it is not safe to call RecvMsg on the same stream in different goroutines. + // Deprecated: See ClientStream and ServerStream documentation instead. RecvMsg(m interface{}) error } -// ClientStream defines the interface a client stream has to satisfy. +// ClientStream defines the client-side behavior of a streaming RPC. +// +// All errors returned from ClientStream methods are compatible with the +// status package. type ClientStream interface { // Header returns the header metadata received from the server if there // is any. It blocks if the metadata is not ready to read. @@ -89,15 +85,42 @@ type ClientStream interface { // stream.Recv has returned a non-nil error (including io.EOF). Trailer() metadata.MD // CloseSend closes the send direction of the stream. It closes the stream - // when non-nil error is met. + // when non-nil error is met. It is also not safe to call CloseSend + // concurrently with SendMsg. CloseSend() error - // Stream.SendMsg() may return a non-nil error when something wrong happens sending - // the request. The returned error indicates the status of this sending, not the final - // status of the RPC. + // Context returns the context for this stream. + // + // It should not be called until after Header or RecvMsg has returned. Once + // called, subsequent client-side retries are disabled. + Context() context.Context + // SendMsg is generally called by generated code. On error, SendMsg aborts + // the stream. If the error was generated by the client, the status is + // returned directly; otherwise, io.EOF is returned and the status of + // the stream may be discovered using RecvMsg. + // + // SendMsg blocks until: + // - There is sufficient flow control to schedule m with the transport, or + // - The stream is done, or + // - The stream breaks. // - // Always call Stream.RecvMsg() to drain the stream and get the final - // status, otherwise there could be leaked resources. - Stream + // SendMsg does not wait until the message is received by the server. An + // untimely stream closure may result in lost messages. To ensure delivery, + // users should ensure the RPC completed successfully using RecvMsg. + // + // It is safe to have a goroutine calling SendMsg and another goroutine + // calling RecvMsg on the same stream at the same time, but it is not safe + // to call SendMsg on the same stream in different goroutines. It is also + // not safe to call CloseSend concurrently with SendMsg. + SendMsg(m interface{}) error + // RecvMsg blocks until it receives a message into m or the stream is + // done. It returns io.EOF when the stream completes successfully. On + // any other error, the stream is aborted and the error contains the RPC + // status. + // + // It is safe to have a goroutine calling SendMsg and another goroutine + // calling RecvMsg on the same stream at the same time, but it is not + // safe to call RecvMsg on the same stream in different goroutines. + RecvMsg(m interface{}) error } // NewStream creates a new Stream for the client side. This is typically @@ -128,8 +151,6 @@ func (cc *ClientConn) NewStream(ctx context.Context, desc *StreamDesc, method st } // NewClientStream is a wrapper for ClientConn.NewStream. -// -// DEPRECATED: Use ClientConn.NewStream instead. func NewClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (ClientStream, error) { return cc.NewStream(ctx, desc, method, opts...) } @@ -144,6 +165,11 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth }() } c := defaultCallInfo() + // Provide an opportunity for the first RPC to see the first service config + // provided by the resolver. + if err := cc.waitForResolvedAddrs(ctx); err != nil { + return nil, err + } mc := cc.GetMethodConfig(method) if mc.WaitForReady != nil { c.failFast = !*mc.WaitForReady @@ -178,13 +204,8 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth } callHdr := &transport.CallHdr{ - Host: cc.authority, - Method: method, - // If it's not client streaming, we should already have the request to be sent, - // so we don't flush the header. - // If it's client streaming, the user may never send a request or send it any - // time soon, so we ask the transport to flush the header. - Flush: desc.ClientStreams, + Host: cc.authority, + Method: method, ContentSubtype: c.contentSubtype, } @@ -218,15 +239,6 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth } trInfo.tr.LazyLog(&trInfo.firstLine, false) ctx = trace.NewContext(ctx, trInfo.tr) - defer func() { - if err != nil { - // Need to call tr.finish() if error is returned. - // Because tr will not be returned to caller. - trInfo.tr.LazyPrintf("RPC: [%v]", err) - trInfo.tr.SetError() - trInfo.tr.Finish() - } - }() } ctx = newContextWithRPCInfo(ctx, c.failFast) sh := cc.dopts.copts.StatsHandler @@ -240,80 +252,59 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth FailFast: c.failFast, } sh.HandleRPC(ctx, begin) - defer func() { - if err != nil { - // Only handle end stats if err != nil. - end := &stats.End{ - Client: true, - Error: err, - BeginTime: beginTime, - EndTime: time.Now(), - } - sh.HandleRPC(ctx, end) - } - }() } - var ( - t transport.ClientTransport - s *transport.Stream - done func(balancer.DoneInfo) - ) - for { - // Check to make sure the context has expired. This will prevent us from - // looping forever if an error occurs for wait-for-ready RPCs where no data - // is sent on the wire. - select { - case <-ctx.Done(): - return nil, toRPCErr(ctx.Err()) - default: - } + cs := &clientStream{ + callHdr: callHdr, + ctx: ctx, + methodConfig: &mc, + opts: opts, + callInfo: c, + cc: cc, + desc: desc, + codec: c.codec, + cp: cp, + comp: comp, + cancel: cancel, + beginTime: beginTime, + firstAttempt: true, + } + if !cc.dopts.disableRetry { + cs.retryThrottler = cc.retryThrottler.Load().(*retryThrottler) + } + cs.binlog = binarylog.GetMethodLogger(method) - t, done, err = cc.getTransport(ctx, c.failFast) - if err != nil { - return nil, err - } + cs.callInfo.stream = cs + // Only this initial attempt has stats/tracing. + // TODO(dfawley): move to newAttempt when per-attempt stats are implemented. + if err := cs.newAttemptLocked(sh, trInfo); err != nil { + cs.finish(err) + return nil, err + } - s, err = t.NewStream(ctx, callHdr) - if err != nil { - if done != nil { - done(balancer.DoneInfo{Err: err}) - done = nil - } - // In the event of any error from NewStream, we never attempted to write - // anything to the wire, so we can retry indefinitely for non-fail-fast - // RPCs. - if !c.failFast { - continue + op := func(a *csAttempt) error { return a.newStream() } + if err := cs.withRetry(op, func() { cs.bufferForRetryLocked(0, op) }); err != nil { + cs.finish(err) + return nil, err + } + + if cs.binlog != nil { + md, _ := metadata.FromOutgoingContext(ctx) + logEntry := &binarylog.ClientHeader{ + OnClientSide: true, + Header: md, + MethodName: method, + Authority: cs.cc.authority, + } + if deadline, ok := ctx.Deadline(); ok { + logEntry.Timeout = deadline.Sub(time.Now()) + if logEntry.Timeout < 0 { + logEntry.Timeout = 0 } - return nil, toRPCErr(err) } - break + cs.binlog.Log(logEntry) } - cs := &clientStream{ - opts: opts, - c: c, - cc: cc, - desc: desc, - codec: c.codec, - cp: cp, - comp: comp, - cancel: cancel, - attempt: &csAttempt{ - t: t, - s: s, - p: &parser{r: s}, - done: done, - dc: cc.dopts.dc, - ctx: ctx, - trInfo: trInfo, - statsHandler: sh, - beginTime: beginTime, - }, - } - cs.c.stream = cs - cs.attempt.cs = cs if desc != unaryStreamDesc { // Listen on cc and stream contexts to cleanup when the user closes the // ClientConn or cancels the stream context. In all other cases, an error @@ -332,12 +323,45 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth return cs, nil } +func (cs *clientStream) newAttemptLocked(sh stats.Handler, trInfo traceInfo) error { + cs.attempt = &csAttempt{ + cs: cs, + dc: cs.cc.dopts.dc, + statsHandler: sh, + trInfo: trInfo, + } + + if err := cs.ctx.Err(); err != nil { + return toRPCErr(err) + } + t, done, err := cs.cc.getTransport(cs.ctx, cs.callInfo.failFast, cs.callHdr.Method) + if err != nil { + return err + } + cs.attempt.t = t + cs.attempt.done = done + return nil +} + +func (a *csAttempt) newStream() error { + cs := a.cs + cs.callHdr.PreviousAttempts = cs.numRetries + s, err := a.t.NewStream(cs.ctx, cs.callHdr) + if err != nil { + return toRPCErr(err) + } + cs.attempt.s = s + cs.attempt.p = &parser{r: s} + return nil +} + // clientStream implements a client side Stream. type clientStream struct { - opts []CallOption - c *callInfo - cc *ClientConn - desc *StreamDesc + callHdr *transport.CallHdr + opts []CallOption + callInfo *callInfo + cc *ClientConn + desc *StreamDesc codec baseCodec cp Compressor @@ -345,13 +369,34 @@ type clientStream struct { cancel context.CancelFunc // cancels all attempts - sentLast bool // sent an end stream + sentLast bool // sent an end stream + beginTime time.Time + + methodConfig *MethodConfig + + ctx context.Context // the application's context, wrapped by stats/tracing + + retryThrottler *retryThrottler // The throttler active when the RPC began. - mu sync.Mutex // guards finished - finished bool // TODO: replace with atomic cmpxchg or sync.Once? + binlog *binarylog.MethodLogger // Binary logger, can be nil. + // serverHeaderBinlogged is a boolean for whether server header has been + // logged. Server header will be logged when the first time one of those + // happens: stream.Header(), stream.Recv(). + // + // It's only read and used by Recv() and Header(), so it doesn't need to be + // synchronized. + serverHeaderBinlogged bool - attempt *csAttempt // the active client stream attempt + mu sync.Mutex + firstAttempt bool // if true, transparent retry is valid + numRetries int // exclusive of transparent retry attempt(s) + numRetriesSincePushback int // retries since pushback; to reset backoff + finished bool // TODO: replace with atomic cmpxchg or sync.Once? + attempt *csAttempt // the active client stream attempt // TODO(hedging): hedging will have multiple attempts simultaneously. + committed bool // active attempt committed for retry? + buffer []func(a *csAttempt) error // operations to replay on retry + bufferSize int // current size of buffer } // csAttempt implements a single transport stream attempt within a @@ -363,53 +408,362 @@ type csAttempt struct { p *parser done func(balancer.DoneInfo) + finished bool dc Decompressor decomp encoding.Compressor decompSet bool - ctx context.Context // the application's context, wrapped by stats/tracing - mu sync.Mutex // guards trInfo.tr // trInfo.tr is set when created (if EnableTracing is true), // and cleared when the finish method is called. trInfo traceInfo statsHandler stats.Handler - beginTime time.Time +} + +func (cs *clientStream) commitAttemptLocked() { + cs.committed = true + cs.buffer = nil +} + +func (cs *clientStream) commitAttempt() { + cs.mu.Lock() + cs.commitAttemptLocked() + cs.mu.Unlock() +} + +// shouldRetry returns nil if the RPC should be retried; otherwise it returns +// the error that should be returned by the operation. +func (cs *clientStream) shouldRetry(err error) error { + if cs.attempt.s == nil && !cs.callInfo.failFast { + // In the event of any error from NewStream (attempt.s == nil), we + // never attempted to write anything to the wire, so we can retry + // indefinitely for non-fail-fast RPCs. + return nil + } + if cs.finished || cs.committed { + // RPC is finished or committed; cannot retry. + return err + } + // Wait for the trailers. + if cs.attempt.s != nil { + <-cs.attempt.s.Done() + } + if cs.firstAttempt && !cs.callInfo.failFast && (cs.attempt.s == nil || cs.attempt.s.Unprocessed()) { + // First attempt, wait-for-ready, stream unprocessed: transparently retry. + cs.firstAttempt = false + return nil + } + cs.firstAttempt = false + if cs.cc.dopts.disableRetry { + return err + } + + pushback := 0 + hasPushback := false + if cs.attempt.s != nil { + if to, toErr := cs.attempt.s.TrailersOnly(); toErr != nil { + // Context error; stop now. + return toErr + } else if !to { + return err + } + + // TODO(retry): Move down if the spec changes to not check server pushback + // before considering this a failure for throttling. + sps := cs.attempt.s.Trailer()["grpc-retry-pushback-ms"] + if len(sps) == 1 { + var e error + if pushback, e = strconv.Atoi(sps[0]); e != nil || pushback < 0 { + grpclog.Infof("Server retry pushback specified to abort (%q).", sps[0]) + cs.retryThrottler.throttle() // This counts as a failure for throttling. + return err + } + hasPushback = true + } else if len(sps) > 1 { + grpclog.Warningf("Server retry pushback specified multiple values (%q); not retrying.", sps) + cs.retryThrottler.throttle() // This counts as a failure for throttling. + return err + } + } + + var code codes.Code + if cs.attempt.s != nil { + code = cs.attempt.s.Status().Code() + } else { + code = status.Convert(err).Code() + } + + rp := cs.methodConfig.retryPolicy + if rp == nil || !rp.retryableStatusCodes[code] { + return err + } + + // Note: the ordering here is important; we count this as a failure + // only if the code matched a retryable code. + if cs.retryThrottler.throttle() { + return err + } + if cs.numRetries+1 >= rp.maxAttempts { + return err + } + + var dur time.Duration + if hasPushback { + dur = time.Millisecond * time.Duration(pushback) + cs.numRetriesSincePushback = 0 + } else { + fact := math.Pow(rp.backoffMultiplier, float64(cs.numRetriesSincePushback)) + cur := float64(rp.initialBackoff) * fact + if max := float64(rp.maxBackoff); cur > max { + cur = max + } + dur = time.Duration(grpcrand.Int63n(int64(cur))) + cs.numRetriesSincePushback++ + } + + // TODO(dfawley): we could eagerly fail here if dur puts us past the + // deadline, but unsure if it is worth doing. + t := time.NewTimer(dur) + select { + case <-t.C: + cs.numRetries++ + return nil + case <-cs.ctx.Done(): + t.Stop() + return status.FromContextError(cs.ctx.Err()).Err() + } +} + +// Returns nil if a retry was performed and succeeded; error otherwise. +func (cs *clientStream) retryLocked(lastErr error) error { + for { + cs.attempt.finish(lastErr) + if err := cs.shouldRetry(lastErr); err != nil { + cs.commitAttemptLocked() + return err + } + if err := cs.newAttemptLocked(nil, traceInfo{}); err != nil { + return err + } + if lastErr = cs.replayBufferLocked(); lastErr == nil { + return nil + } + } } func (cs *clientStream) Context() context.Context { - // TODO(retry): commit the current attempt (the context has peer-aware data). - return cs.attempt.context() + cs.commitAttempt() + // No need to lock before using attempt, since we know it is committed and + // cannot change. + return cs.attempt.s.Context() +} + +func (cs *clientStream) withRetry(op func(a *csAttempt) error, onSuccess func()) error { + cs.mu.Lock() + for { + if cs.committed { + cs.mu.Unlock() + return op(cs.attempt) + } + a := cs.attempt + cs.mu.Unlock() + err := op(a) + cs.mu.Lock() + if a != cs.attempt { + // We started another attempt already. + continue + } + if err == io.EOF { + <-a.s.Done() + } + if err == nil || (err == io.EOF && a.s.Status().Code() == codes.OK) { + onSuccess() + cs.mu.Unlock() + return err + } + if err := cs.retryLocked(err); err != nil { + cs.mu.Unlock() + return err + } + } } func (cs *clientStream) Header() (metadata.MD, error) { - m, err := cs.attempt.header() + var m metadata.MD + err := cs.withRetry(func(a *csAttempt) error { + var err error + m, err = a.s.Header() + return toRPCErr(err) + }, cs.commitAttemptLocked) if err != nil { - // TODO(retry): maybe retry on error or commit attempt on success. - err = toRPCErr(err) cs.finish(err) + return nil, err + } + if cs.binlog != nil && !cs.serverHeaderBinlogged { + // Only log if binary log is on and header has not been logged. + logEntry := &binarylog.ServerHeader{ + OnClientSide: true, + Header: m, + PeerAddr: nil, + } + if peer, ok := peer.FromContext(cs.Context()); ok { + logEntry.PeerAddr = peer.Addr + } + cs.binlog.Log(logEntry) + cs.serverHeaderBinlogged = true } return m, err } func (cs *clientStream) Trailer() metadata.MD { - // TODO(retry): on error, maybe retry (trailers-only). - return cs.attempt.trailer() + // On RPC failure, we never need to retry, because usage requires that + // RecvMsg() returned a non-nil error before calling this function is valid. + // We would have retried earlier if necessary. + // + // Commit the attempt anyway, just in case users are not following those + // directions -- it will prevent races and should not meaningfully impact + // performance. + cs.commitAttempt() + if cs.attempt.s == nil { + return nil + } + return cs.attempt.s.Trailer() +} + +func (cs *clientStream) replayBufferLocked() error { + a := cs.attempt + for _, f := range cs.buffer { + if err := f(a); err != nil { + return err + } + } + return nil +} + +func (cs *clientStream) bufferForRetryLocked(sz int, op func(a *csAttempt) error) { + // Note: we still will buffer if retry is disabled (for transparent retries). + if cs.committed { + return + } + cs.bufferSize += sz + if cs.bufferSize > cs.callInfo.maxRetryRPCBufferSize { + cs.commitAttemptLocked() + return + } + cs.buffer = append(cs.buffer, op) } func (cs *clientStream) SendMsg(m interface{}) (err error) { - // TODO(retry): buffer message for replaying if not committed. - return cs.attempt.sendMsg(m) + defer func() { + if err != nil && err != io.EOF { + // Call finish on the client stream for errors generated by this SendMsg + // call, as these indicate problems created by this client. (Transport + // errors are converted to an io.EOF error in csAttempt.sendMsg; the real + // error will be returned from RecvMsg eventually in that case, or be + // retried.) + cs.finish(err) + } + }() + if cs.sentLast { + return status.Errorf(codes.Internal, "SendMsg called after CloseSend") + } + if !cs.desc.ClientStreams { + cs.sentLast = true + } + data, err := encode(cs.codec, m) + if err != nil { + return err + } + compData, err := compress(data, cs.cp, cs.comp) + if err != nil { + return err + } + hdr, payload := msgHeader(data, compData) + // TODO(dfawley): should we be checking len(data) instead? + if len(payload) > *cs.callInfo.maxSendMessageSize { + return status.Errorf(codes.ResourceExhausted, "trying to send message larger than max (%d vs. %d)", len(payload), *cs.callInfo.maxSendMessageSize) + } + msgBytes := data // Store the pointer before setting to nil. For binary logging. + op := func(a *csAttempt) error { + err := a.sendMsg(m, hdr, payload, data) + // nil out the message and uncomp when replaying; they are only needed for + // stats which is disabled for subsequent attempts. + m, data = nil, nil + return err + } + err = cs.withRetry(op, func() { cs.bufferForRetryLocked(len(hdr)+len(payload), op) }) + if cs.binlog != nil && err == nil { + cs.binlog.Log(&binarylog.ClientMessage{ + OnClientSide: true, + Message: msgBytes, + }) + } + return } -func (cs *clientStream) RecvMsg(m interface{}) (err error) { - // TODO(retry): maybe retry on error or commit attempt on success. - return cs.attempt.recvMsg(m) +func (cs *clientStream) RecvMsg(m interface{}) error { + if cs.binlog != nil && !cs.serverHeaderBinlogged { + // Call Header() to binary log header if it's not already logged. + cs.Header() + } + var recvInfo *payloadInfo + if cs.binlog != nil { + recvInfo = &payloadInfo{} + } + err := cs.withRetry(func(a *csAttempt) error { + return a.recvMsg(m, recvInfo) + }, cs.commitAttemptLocked) + if cs.binlog != nil && err == nil { + cs.binlog.Log(&binarylog.ServerMessage{ + OnClientSide: true, + Message: recvInfo.uncompressedBytes, + }) + } + if err != nil || !cs.desc.ServerStreams { + // err != nil or non-server-streaming indicates end of stream. + cs.finish(err) + + if cs.binlog != nil { + // finish will not log Trailer. Log Trailer here. + logEntry := &binarylog.ServerTrailer{ + OnClientSide: true, + Trailer: cs.Trailer(), + Err: err, + } + if logEntry.Err == io.EOF { + logEntry.Err = nil + } + if peer, ok := peer.FromContext(cs.Context()); ok { + logEntry.PeerAddr = peer.Addr + } + cs.binlog.Log(logEntry) + } + } + return err } func (cs *clientStream) CloseSend() error { - cs.attempt.closeSend() + if cs.sentLast { + // TODO: return an error and finish the stream instead, due to API misuse? + return nil + } + cs.sentLast = true + op := func(a *csAttempt) error { + a.t.Write(a.s, nil, nil, &transport.Options{Last: true}) + // Always return nil; io.EOF is the only error that might make sense + // instead, but there is no need to signal the client to call RecvMsg + // as the only use left for the stream after CloseSend is to call + // RecvMsg. This also matches historical behavior. + return nil + } + cs.withRetry(op, func() { cs.bufferForRetryLocked(0, op) }) + if cs.binlog != nil { + cs.binlog.Log(&binarylog.ClientHalfClose{ + OnClientSide: true, + }) + } + // We never returned an error here for reasons. return nil } @@ -424,7 +778,21 @@ func (cs *clientStream) finish(err error) { return } cs.finished = true + cs.commitAttemptLocked() cs.mu.Unlock() + // For binary logging. only log cancel in finish (could be caused by RPC ctx + // canceled or ClientConn closed). Trailer will be logged in RecvMsg. + // + // Only one of cancel or trailer needs to be logged. In the cases where + // users don't call RecvMsg, users must have already canceled the RPC. + if cs.binlog != nil && status.Code(err) == codes.Canceled { + cs.binlog.Log(&binarylog.Cancel{ + OnClientSide: true, + }) + } + if err == nil { + cs.retryThrottler.successfulRPC() + } if channelz.IsOn() { if err != nil { cs.cc.incrCallsFailed() @@ -432,46 +800,20 @@ func (cs *clientStream) finish(err error) { cs.cc.incrCallsSucceeded() } } - // TODO(retry): commit current attempt if necessary. - cs.attempt.finish(err) - for _, o := range cs.opts { - o.after(cs.c) + if cs.attempt != nil { + cs.attempt.finish(err) + } + // after functions all rely upon having a stream. + if cs.attempt.s != nil { + for _, o := range cs.opts { + o.after(cs.callInfo) + } } cs.cancel() } -func (a *csAttempt) context() context.Context { - return a.s.Context() -} - -func (a *csAttempt) header() (metadata.MD, error) { - return a.s.Header() -} - -func (a *csAttempt) trailer() metadata.MD { - return a.s.Trailer() -} - -func (a *csAttempt) sendMsg(m interface{}) (err error) { - // TODO Investigate how to signal the stats handling party. - // generate error stats if err != nil && err != io.EOF? +func (a *csAttempt) sendMsg(m interface{}, hdr, payld, data []byte) error { cs := a.cs - defer func() { - // For non-client-streaming RPCs, we return nil instead of EOF on success - // because the generated code requires it. finish is not called; RecvMsg() - // will call it with the stream's status independently. - if err == io.EOF && !cs.desc.ClientStreams { - err = nil - } - if err != nil && err != io.EOF { - // Call finish on the client stream for errors generated by this SendMsg - // call, as these indicate problems created by this client. (Transport - // errors are converted to an io.EOF error below; the real error will be - // returned from RecvMsg eventually in that case, or be retried.) - cs.finish(err) - } - }() - // TODO: Check cs.sentLast and error if we already ended the stream. if EnableTracing { a.mu.Lock() if a.trInfo.tr != nil { @@ -479,50 +821,30 @@ func (a *csAttempt) sendMsg(m interface{}) (err error) { } a.mu.Unlock() } - data, err := encode(cs.codec, m) - if err != nil { - return err - } - compData, err := compress(data, cs.cp, cs.comp) - if err != nil { - return err - } - hdr, payload := msgHeader(data, compData) - // TODO(dfawley): should we be checking len(data) instead? - if len(payload) > *cs.c.maxSendMessageSize { - return status.Errorf(codes.ResourceExhausted, "trying to send message larger than max (%d vs. %d)", len(payload), *cs.c.maxSendMessageSize) + if err := a.t.Write(a.s, hdr, payld, &transport.Options{Last: !cs.desc.ClientStreams}); err != nil { + if !cs.desc.ClientStreams { + // For non-client-streaming RPCs, we return nil instead of EOF on error + // because the generated code requires it. finish is not called; RecvMsg() + // will call it with the stream's status independently. + return nil + } + return io.EOF } - - if !cs.desc.ClientStreams { - cs.sentLast = true + if a.statsHandler != nil { + a.statsHandler.HandleRPC(cs.ctx, outPayload(true, m, data, payld, time.Now())) } - err = a.t.Write(a.s, hdr, payload, &transport.Options{Last: !cs.desc.ClientStreams}) - if err == nil { - if a.statsHandler != nil { - a.statsHandler.HandleRPC(a.ctx, outPayload(true, m, data, payload, time.Now())) - } - if channelz.IsOn() { - a.t.IncrMsgSent() - } - return nil + if channelz.IsOn() { + a.t.IncrMsgSent() } - return io.EOF + return nil } -func (a *csAttempt) recvMsg(m interface{}) (err error) { +func (a *csAttempt) recvMsg(m interface{}, payInfo *payloadInfo) (err error) { cs := a.cs - defer func() { - if err != nil || !cs.desc.ServerStreams { - // err != nil or non-server-streaming indicates end of stream. - cs.finish(err) - } - }() - var inPayload *stats.InPayload - if a.statsHandler != nil { - inPayload = &stats.InPayload{ - Client: true, - } + if a.statsHandler != nil && payInfo == nil { + payInfo = &payloadInfo{} } + if !a.decompSet { // Block until we receive headers containing received message encoding. if ct := a.s.RecvCompress(); ct != "" && ct != encoding.Identity { @@ -539,7 +861,7 @@ func (a *csAttempt) recvMsg(m interface{}) (err error) { // Only initialize this state once per stream. a.decompSet = true } - err = recv(a.p, cs.codec, a.s, a.dc, m, *cs.c.maxReceiveMessageSize, inPayload, a.decomp) + err = recv(a.p, cs.codec, a.s, a.dc, m, *cs.callInfo.maxReceiveMessageSize, payInfo, a.decomp) if err != nil { if err == io.EOF { if statusErr := a.s.Status().Err(); statusErr != nil { @@ -556,8 +878,15 @@ func (a *csAttempt) recvMsg(m interface{}) (err error) { } a.mu.Unlock() } - if inPayload != nil { - a.statsHandler.HandleRPC(a.ctx, inPayload) + if a.statsHandler != nil { + a.statsHandler.HandleRPC(cs.ctx, &stats.InPayload{ + Client: true, + RecvTime: time.Now(), + Payload: m, + // TODO truncate large payload. + Data: payInfo.uncompressedBytes, + Length: len(payInfo.uncompressedBytes), + }) } if channelz.IsOn() { a.t.IncrMsgRecv() @@ -566,10 +895,9 @@ func (a *csAttempt) recvMsg(m interface{}) (err error) { // Subsequent messages should be received by subsequent RecvMsg calls. return nil } - // Special handling for non-server-stream rpcs. // This recv expects EOF or errors, so we don't collect inPayload. - err = recv(a.p, cs.codec, a.s, a.dc, m, *cs.c.maxReceiveMessageSize, nil, a.decomp) + err = recv(a.p, cs.codec, a.s, a.dc, m, *cs.callInfo.maxReceiveMessageSize, nil, a.decomp) if err == nil { return toRPCErr(errors.New("grpc: client streaming protocol violation: get , want ")) } @@ -579,37 +907,43 @@ func (a *csAttempt) recvMsg(m interface{}) (err error) { return toRPCErr(err) } -func (a *csAttempt) closeSend() { - cs := a.cs - if cs.sentLast { - return - } - cs.sentLast = true - cs.attempt.t.Write(cs.attempt.s, nil, nil, &transport.Options{Last: true}) - // We ignore errors from Write. Any error it would return would also be - // returned by a subsequent RecvMsg call, and the user is supposed to always - // finish the stream by calling RecvMsg until it returns err != nil. -} - func (a *csAttempt) finish(err error) { a.mu.Lock() - a.t.CloseStream(a.s, err) + if a.finished { + a.mu.Unlock() + return + } + a.finished = true + if err == io.EOF { + // Ending a stream with EOF indicates a success. + err = nil + } + if a.s != nil { + a.t.CloseStream(a.s, err) + } if a.done != nil { + br := false + var tr metadata.MD + if a.s != nil { + br = a.s.BytesReceived() + tr = a.s.Trailer() + } a.done(balancer.DoneInfo{ Err: err, - BytesSent: true, - BytesReceived: a.s.BytesReceived(), + Trailer: tr, + BytesSent: a.s != nil, + BytesReceived: br, }) } if a.statsHandler != nil { end := &stats.End{ Client: true, - BeginTime: a.beginTime, + BeginTime: a.cs.beginTime, EndTime: time.Now(), Error: err, } - a.statsHandler.HandleRPC(a.ctx, end) + a.statsHandler.HandleRPC(a.cs.ctx, end) } if a.trInfo.tr != nil { if err == nil { @@ -624,7 +958,303 @@ func (a *csAttempt) finish(err error) { a.mu.Unlock() } -// ServerStream defines the interface a server stream has to satisfy. +func (ac *addrConn) newClientStream(ctx context.Context, desc *StreamDesc, method string, t transport.ClientTransport, opts ...CallOption) (_ ClientStream, err error) { + ac.mu.Lock() + if ac.transport != t { + ac.mu.Unlock() + return nil, status.Error(codes.Canceled, "the provided transport is no longer valid to use") + } + // transition to CONNECTING state when an attempt starts + if ac.state != connectivity.Connecting { + ac.updateConnectivityState(connectivity.Connecting) + ac.cc.handleSubConnStateChange(ac.acbw, ac.state) + } + ac.mu.Unlock() + + if t == nil { + // TODO: return RPC error here? + return nil, errors.New("transport provided is nil") + } + // defaultCallInfo contains unnecessary info(i.e. failfast, maxRetryRPCBufferSize), so we just initialize an empty struct. + c := &callInfo{} + + for _, o := range opts { + if err := o.before(c); err != nil { + return nil, toRPCErr(err) + } + } + c.maxReceiveMessageSize = getMaxSize(nil, c.maxReceiveMessageSize, defaultClientMaxReceiveMessageSize) + c.maxSendMessageSize = getMaxSize(nil, c.maxSendMessageSize, defaultServerMaxSendMessageSize) + + // Possible context leak: + // The cancel function for the child context we create will only be called + // when RecvMsg returns a non-nil error, if the ClientConn is closed, or if + // an error is generated by SendMsg. + // https://github.com/grpc/grpc-go/issues/1818. + ctx, cancel := context.WithCancel(ctx) + defer func() { + if err != nil { + cancel() + } + }() + + if err := setCallInfoCodec(c); err != nil { + return nil, err + } + + callHdr := &transport.CallHdr{ + Host: ac.cc.authority, + Method: method, + ContentSubtype: c.contentSubtype, + } + + // Set our outgoing compression according to the UseCompressor CallOption, if + // set. In that case, also find the compressor from the encoding package. + // Otherwise, use the compressor configured by the WithCompressor DialOption, + // if set. + var cp Compressor + var comp encoding.Compressor + if ct := c.compressorType; ct != "" { + callHdr.SendCompress = ct + if ct != encoding.Identity { + comp = encoding.GetCompressor(ct) + if comp == nil { + return nil, status.Errorf(codes.Internal, "grpc: Compressor is not installed for requested grpc-encoding %q", ct) + } + } + } else if ac.cc.dopts.cp != nil { + callHdr.SendCompress = ac.cc.dopts.cp.Type() + cp = ac.cc.dopts.cp + } + if c.creds != nil { + callHdr.Creds = c.creds + } + + as := &addrConnStream{ + callHdr: callHdr, + ac: ac, + ctx: ctx, + cancel: cancel, + opts: opts, + callInfo: c, + desc: desc, + codec: c.codec, + cp: cp, + comp: comp, + t: t, + } + + as.callInfo.stream = as + s, err := as.t.NewStream(as.ctx, as.callHdr) + if err != nil { + err = toRPCErr(err) + return nil, err + } + as.s = s + as.p = &parser{r: s} + ac.incrCallsStarted() + if desc != unaryStreamDesc { + // Listen on cc and stream contexts to cleanup when the user closes the + // ClientConn or cancels the stream context. In all other cases, an error + // should already be injected into the recv buffer by the transport, which + // the client will eventually receive, and then we will cancel the stream's + // context in clientStream.finish. + go func() { + select { + case <-ac.ctx.Done(): + as.finish(status.Error(codes.Canceled, "grpc: the SubConn is closing")) + case <-ctx.Done(): + as.finish(toRPCErr(ctx.Err())) + } + }() + } + return as, nil +} + +type addrConnStream struct { + s *transport.Stream + ac *addrConn + callHdr *transport.CallHdr + cancel context.CancelFunc + opts []CallOption + callInfo *callInfo + t transport.ClientTransport + ctx context.Context + sentLast bool + desc *StreamDesc + codec baseCodec + cp Compressor + comp encoding.Compressor + decompSet bool + dc Decompressor + decomp encoding.Compressor + p *parser + done func(balancer.DoneInfo) + mu sync.Mutex + finished bool +} + +func (as *addrConnStream) Header() (metadata.MD, error) { + m, err := as.s.Header() + if err != nil { + as.finish(toRPCErr(err)) + } + return m, err +} + +func (as *addrConnStream) Trailer() metadata.MD { + return as.s.Trailer() +} + +func (as *addrConnStream) CloseSend() error { + if as.sentLast { + // TODO: return an error and finish the stream instead, due to API misuse? + return nil + } + as.sentLast = true + + as.t.Write(as.s, nil, nil, &transport.Options{Last: true}) + // Always return nil; io.EOF is the only error that might make sense + // instead, but there is no need to signal the client to call RecvMsg + // as the only use left for the stream after CloseSend is to call + // RecvMsg. This also matches historical behavior. + return nil +} + +func (as *addrConnStream) Context() context.Context { + return as.s.Context() +} + +func (as *addrConnStream) SendMsg(m interface{}) (err error) { + defer func() { + if err != nil && err != io.EOF { + // Call finish on the client stream for errors generated by this SendMsg + // call, as these indicate problems created by this client. (Transport + // errors are converted to an io.EOF error in csAttempt.sendMsg; the real + // error will be returned from RecvMsg eventually in that case, or be + // retried.) + as.finish(err) + } + }() + if as.sentLast { + return status.Errorf(codes.Internal, "SendMsg called after CloseSend") + } + if !as.desc.ClientStreams { + as.sentLast = true + } + data, err := encode(as.codec, m) + if err != nil { + return err + } + compData, err := compress(data, as.cp, as.comp) + if err != nil { + return err + } + hdr, payld := msgHeader(data, compData) + // TODO(dfawley): should we be checking len(data) instead? + if len(payld) > *as.callInfo.maxSendMessageSize { + return status.Errorf(codes.ResourceExhausted, "trying to send message larger than max (%d vs. %d)", len(payld), *as.callInfo.maxSendMessageSize) + } + + if err := as.t.Write(as.s, hdr, payld, &transport.Options{Last: !as.desc.ClientStreams}); err != nil { + if !as.desc.ClientStreams { + // For non-client-streaming RPCs, we return nil instead of EOF on error + // because the generated code requires it. finish is not called; RecvMsg() + // will call it with the stream's status independently. + return nil + } + return io.EOF + } + + if channelz.IsOn() { + as.t.IncrMsgSent() + } + return nil +} + +func (as *addrConnStream) RecvMsg(m interface{}) (err error) { + defer func() { + if err != nil || !as.desc.ServerStreams { + // err != nil or non-server-streaming indicates end of stream. + as.finish(err) + } + }() + + if !as.decompSet { + // Block until we receive headers containing received message encoding. + if ct := as.s.RecvCompress(); ct != "" && ct != encoding.Identity { + if as.dc == nil || as.dc.Type() != ct { + // No configured decompressor, or it does not match the incoming + // message encoding; attempt to find a registered compressor that does. + as.dc = nil + as.decomp = encoding.GetCompressor(ct) + } + } else { + // No compression is used; disable our decompressor. + as.dc = nil + } + // Only initialize this state once per stream. + as.decompSet = true + } + err = recv(as.p, as.codec, as.s, as.dc, m, *as.callInfo.maxReceiveMessageSize, nil, as.decomp) + if err != nil { + if err == io.EOF { + if statusErr := as.s.Status().Err(); statusErr != nil { + return statusErr + } + return io.EOF // indicates successful end of stream. + } + return toRPCErr(err) + } + + if channelz.IsOn() { + as.t.IncrMsgRecv() + } + if as.desc.ServerStreams { + // Subsequent messages should be received by subsequent RecvMsg calls. + return nil + } + + // Special handling for non-server-stream rpcs. + // This recv expects EOF or errors, so we don't collect inPayload. + err = recv(as.p, as.codec, as.s, as.dc, m, *as.callInfo.maxReceiveMessageSize, nil, as.decomp) + if err == nil { + return toRPCErr(errors.New("grpc: client streaming protocol violation: get , want ")) + } + if err == io.EOF { + return as.s.Status().Err() // non-server streaming Recv returns nil on success + } + return toRPCErr(err) +} + +func (as *addrConnStream) finish(err error) { + as.mu.Lock() + if as.finished { + as.mu.Unlock() + return + } + as.finished = true + if err == io.EOF { + // Ending a stream with EOF indicates a success. + err = nil + } + if as.s != nil { + as.t.CloseStream(as.s, err) + } + + if err != nil { + as.ac.incrCallsFailed() + } else { + as.ac.incrCallsSucceeded() + } + as.cancel() + as.mu.Unlock() +} + +// ServerStream defines the server-side behavior of a streaming RPC. +// +// All errors returned from ServerStream methods are compatible with the +// status package. type ServerStream interface { // SetHeader sets the header metadata. It may be called multiple times. // When call multiple times, all the provided metadata will be merged. @@ -640,7 +1270,32 @@ type ServerStream interface { // SetTrailer sets the trailer metadata which will be sent with the RPC status. // When called more than once, all the provided metadata will be merged. SetTrailer(metadata.MD) - Stream + // Context returns the context for this stream. + Context() context.Context + // SendMsg sends a message. On error, SendMsg aborts the stream and the + // error is returned directly. + // + // SendMsg blocks until: + // - There is sufficient flow control to schedule m with the transport, or + // - The stream is done, or + // - The stream breaks. + // + // SendMsg does not wait until the message is received by the client. An + // untimely stream closure may result in lost messages. + // + // It is safe to have a goroutine calling SendMsg and another goroutine + // calling RecvMsg on the same stream at the same time, but it is not safe + // to call SendMsg on the same stream in different goroutines. + SendMsg(m interface{}) error + // RecvMsg blocks until it receives a message into m or the stream is + // done. It returns io.EOF when the client has performed a CloseSend. On + // any non-EOF error, the stream is aborted and the error contains the + // RPC status. + // + // It is safe to have a goroutine calling SendMsg and another goroutine + // calling RecvMsg on the same stream at the same time, but it is not + // safe to call RecvMsg on the same stream in different goroutines. + RecvMsg(m interface{}) error } // serverStream implements a server side Stream. @@ -662,6 +1317,15 @@ type serverStream struct { statsHandler stats.Handler + binlog *binarylog.MethodLogger + // serverHeaderBinlogged indicates whether server header has been logged. It + // will happen when one of the following two happens: stream.SendHeader(), + // stream.Send(). + // + // It's only checked in send and sendHeader, doesn't need to be + // synchronized. + serverHeaderBinlogged bool + mu sync.Mutex // protects trInfo.tr after the service handler runs. } @@ -677,7 +1341,15 @@ func (ss *serverStream) SetHeader(md metadata.MD) error { } func (ss *serverStream) SendHeader(md metadata.MD) error { - return ss.t.WriteHeader(ss.s, md) + err := ss.t.WriteHeader(ss.s, md) + if ss.binlog != nil && !ss.serverHeaderBinlogged { + h, _ := ss.s.Header() + ss.binlog.Log(&binarylog.ServerHeader{ + Header: h, + }) + ss.serverHeaderBinlogged = true + } + return err } func (ss *serverStream) SetTrailer(md metadata.MD) { @@ -704,6 +1376,12 @@ func (ss *serverStream) SendMsg(m interface{}) (err error) { if err != nil && err != io.EOF { st, _ := status.FromError(toRPCErr(err)) ss.t.WriteStatus(ss.s, st) + // Non-user specified status was sent out. This should be an error + // case (as a server side Cancel maybe). + // + // This is not handled specifically now. User will return a final + // status from the service handler, we will log that error instead. + // This behavior is similar to an interceptor. } if channelz.IsOn() && err == nil { ss.t.IncrMsgSent() @@ -725,6 +1403,18 @@ func (ss *serverStream) SendMsg(m interface{}) (err error) { if err := ss.t.Write(ss.s, hdr, payload, &transport.Options{Last: false}); err != nil { return toRPCErr(err) } + if ss.binlog != nil { + if !ss.serverHeaderBinlogged { + h, _ := ss.s.Header() + ss.binlog.Log(&binarylog.ServerHeader{ + Header: h, + }) + ss.serverHeaderBinlogged = true + } + ss.binlog.Log(&binarylog.ServerMessage{ + Message: data, + }) + } if ss.statsHandler != nil { ss.statsHandler.HandleRPC(ss.s.Context(), outPayload(false, m, data, payload, time.Now())) } @@ -748,17 +1438,26 @@ func (ss *serverStream) RecvMsg(m interface{}) (err error) { if err != nil && err != io.EOF { st, _ := status.FromError(toRPCErr(err)) ss.t.WriteStatus(ss.s, st) + // Non-user specified status was sent out. This should be an error + // case (as a server side Cancel maybe). + // + // This is not handled specifically now. User will return a final + // status from the service handler, we will log that error instead. + // This behavior is similar to an interceptor. } if channelz.IsOn() && err == nil { ss.t.IncrMsgRecv() } }() - var inPayload *stats.InPayload - if ss.statsHandler != nil { - inPayload = &stats.InPayload{} + var payInfo *payloadInfo + if ss.statsHandler != nil || ss.binlog != nil { + payInfo = &payloadInfo{} } - if err := recv(ss.p, ss.codec, ss.s, ss.dc, m, ss.maxReceiveMessageSize, inPayload, ss.decomp); err != nil { + if err := recv(ss.p, ss.codec, ss.s, ss.dc, m, ss.maxReceiveMessageSize, payInfo, ss.decomp); err != nil { if err == io.EOF { + if ss.binlog != nil { + ss.binlog.Log(&binarylog.ClientHalfClose{}) + } return err } if err == io.ErrUnexpectedEOF { @@ -766,8 +1465,19 @@ func (ss *serverStream) RecvMsg(m interface{}) (err error) { } return toRPCErr(err) } - if inPayload != nil { - ss.statsHandler.HandleRPC(ss.s.Context(), inPayload) + if ss.statsHandler != nil { + ss.statsHandler.HandleRPC(ss.s.Context(), &stats.InPayload{ + RecvTime: time.Now(), + Payload: m, + // TODO truncate large payload. + Data: payInfo.uncompressedBytes, + Length: len(payInfo.uncompressedBytes), + }) + } + if ss.binlog != nil { + ss.binlog.Log(&binarylog.ClientMessage{ + Message: payInfo.uncompressedBytes, + }) } return nil } diff --git a/vendor/google.golang.org/grpc/stress/client/main.go b/vendor/google.golang.org/grpc/stress/client/main.go index dab8a9d743a6f44aea48624a6e93aff837c3ee39..82febbc242a5def457d7345bfd00f7fe91d08be8 100644 --- a/vendor/google.golang.org/grpc/stress/client/main.go +++ b/vendor/google.golang.org/grpc/stress/client/main.go @@ -22,6 +22,7 @@ package main import ( + "context" "flag" "fmt" "math/rand" @@ -31,7 +32,6 @@ import ( "sync" "time" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" diff --git a/vendor/google.golang.org/grpc/stress/grpc_testing/metrics.pb.go b/vendor/google.golang.org/grpc/stress/grpc_testing/metrics.pb.go index 31e95d2b89f4022dc51593133e60bbeb45540f87..0a8ad44f0362b785469806c0ed04316c19b1673a 100644 --- a/vendor/google.golang.org/grpc/stress/grpc_testing/metrics.pb.go +++ b/vendor/google.golang.org/grpc/stress/grpc_testing/metrics.pb.go @@ -60,6 +60,13 @@ func (m *GaugeResponse) XXX_DiscardUnknown() { var xxx_messageInfo_GaugeResponse proto.InternalMessageInfo +func (m *GaugeResponse) GetName() string { + if m != nil { + return m.Name + } + return "" +} + type isGaugeResponse_Value interface { isGaugeResponse_Value() } @@ -67,15 +74,19 @@ type isGaugeResponse_Value interface { type GaugeResponse_LongValue struct { LongValue int64 `protobuf:"varint,2,opt,name=long_value,json=longValue,proto3,oneof"` } + type GaugeResponse_DoubleValue struct { DoubleValue float64 `protobuf:"fixed64,3,opt,name=double_value,json=doubleValue,proto3,oneof"` } + type GaugeResponse_StringValue struct { StringValue string `protobuf:"bytes,4,opt,name=string_value,json=stringValue,proto3,oneof"` } -func (*GaugeResponse_LongValue) isGaugeResponse_Value() {} +func (*GaugeResponse_LongValue) isGaugeResponse_Value() {} + func (*GaugeResponse_DoubleValue) isGaugeResponse_Value() {} + func (*GaugeResponse_StringValue) isGaugeResponse_Value() {} func (m *GaugeResponse) GetValue() isGaugeResponse_Value { @@ -85,13 +96,6 @@ func (m *GaugeResponse) GetValue() isGaugeResponse_Value { return nil } -func (m *GaugeResponse) GetName() string { - if m != nil { - return m.Name - } - return "" -} - func (m *GaugeResponse) GetLongValue() int64 { if x, ok := m.GetValue().(*GaugeResponse_LongValue); ok { return x.LongValue diff --git a/vendor/google.golang.org/grpc/stress/metrics_client/main.go b/vendor/google.golang.org/grpc/stress/metrics_client/main.go index 70b024b635c87e33836c7cc7cd9260a066e4dff9..c9a5c8c559f03a45fd1023d1ebf2dc5fdcbe00b5 100644 --- a/vendor/google.golang.org/grpc/stress/metrics_client/main.go +++ b/vendor/google.golang.org/grpc/stress/metrics_client/main.go @@ -19,11 +19,11 @@ package main import ( + "context" "flag" "fmt" "io" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" metricspb "google.golang.org/grpc/stress/grpc_testing" diff --git a/vendor/google.golang.org/grpc/tap/tap.go b/vendor/google.golang.org/grpc/tap/tap.go index 22b8fb50dea5e77e8d6dfbe2d1f5e17ac5f09431..584360f681b81005d67c3de5f9ffd3410666b890 100644 --- a/vendor/google.golang.org/grpc/tap/tap.go +++ b/vendor/google.golang.org/grpc/tap/tap.go @@ -21,7 +21,7 @@ package tap import ( - "golang.org/x/net/context" + "context" ) // Info defines the relevant information needed by the handles. diff --git a/vendor/google.golang.org/grpc/test/balancer_test.go b/vendor/google.golang.org/grpc/test/balancer_test.go new file mode 100644 index 0000000000000000000000000000000000000000..188f5debec72f1a8f5505467dd69634a01183c47 --- /dev/null +++ b/vendor/google.golang.org/grpc/test/balancer_test.go @@ -0,0 +1,190 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package test + +import ( + "context" + "reflect" + "testing" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/balancer" + "google.golang.org/grpc/connectivity" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/internal/leakcheck" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/resolver" + testpb "google.golang.org/grpc/test/grpc_testing" + "google.golang.org/grpc/testdata" +) + +const testBalancerName = "testbalancer" + +// testBalancer creates one subconn with the first address from resolved +// addresses. +// +// It's used to test options for NewSubConn are applies correctly. +type testBalancer struct { + cc balancer.ClientConn + sc balancer.SubConn + + newSubConnOptions balancer.NewSubConnOptions + pickOptions []balancer.PickOptions + doneInfo []balancer.DoneInfo +} + +func (b *testBalancer) Build(cc balancer.ClientConn, opt balancer.BuildOptions) balancer.Balancer { + b.cc = cc + return b +} + +func (*testBalancer) Name() string { + return testBalancerName +} + +func (b *testBalancer) HandleResolvedAddrs(addrs []resolver.Address, err error) { + // Only create a subconn at the first time. + if err == nil && b.sc == nil { + b.sc, err = b.cc.NewSubConn(addrs, b.newSubConnOptions) + if err != nil { + grpclog.Errorf("testBalancer: failed to NewSubConn: %v", err) + return + } + b.cc.UpdateBalancerState(connectivity.Connecting, &picker{sc: b.sc, bal: b}) + b.sc.Connect() + } +} + +func (b *testBalancer) HandleSubConnStateChange(sc balancer.SubConn, s connectivity.State) { + grpclog.Infof("testBalancer: HandleSubConnStateChange: %p, %v", sc, s) + if b.sc != sc { + grpclog.Infof("testBalancer: ignored state change because sc is not recognized") + return + } + if s == connectivity.Shutdown { + b.sc = nil + return + } + + switch s { + case connectivity.Ready, connectivity.Idle: + b.cc.UpdateBalancerState(s, &picker{sc: sc, bal: b}) + case connectivity.Connecting: + b.cc.UpdateBalancerState(s, &picker{err: balancer.ErrNoSubConnAvailable, bal: b}) + case connectivity.TransientFailure: + b.cc.UpdateBalancerState(s, &picker{err: balancer.ErrTransientFailure, bal: b}) + } +} + +func (b *testBalancer) Close() { +} + +type picker struct { + err error + sc balancer.SubConn + bal *testBalancer +} + +func (p *picker) Pick(ctx context.Context, opts balancer.PickOptions) (balancer.SubConn, func(balancer.DoneInfo), error) { + p.bal.pickOptions = append(p.bal.pickOptions, opts) + if p.err != nil { + return nil, nil, p.err + } + return p.sc, func(d balancer.DoneInfo) { p.bal.doneInfo = append(p.bal.doneInfo, d) }, nil +} + +func TestCredsBundleFromBalancer(t *testing.T) { + balancer.Register(&testBalancer{ + newSubConnOptions: balancer.NewSubConnOptions{ + CredsBundle: &testCredsBundle{}, + }, + }) + defer leakcheck.Check(t) + te := newTest(t, env{name: "creds-bundle", network: "tcp", balancer: ""}) + te.tapHandle = authHandle + te.customDialOptions = []grpc.DialOption{ + grpc.WithBalancerName(testBalancerName), + } + creds, err := credentials.NewServerTLSFromFile(testdata.Path("server1.pem"), testdata.Path("server1.key")) + if err != nil { + t.Fatalf("Failed to generate credentials %v", err) + } + te.customServerOptions = []grpc.ServerOption{ + grpc.Creds(creds), + } + te.startServer(&testServer{}) + defer te.tearDown() + + cc := te.clientConn() + tc := testpb.NewTestServiceClient(cc) + if _, err := tc.EmptyCall(context.Background(), &testpb.Empty{}); err != nil { + t.Fatalf("Test failed. Reason: %v", err) + } +} + +func TestPickAndDone(t *testing.T) { + defer leakcheck.Check(t) + for _, e := range listTestEnv() { + testPickAndDone(t, e) + } +} + +func testPickAndDone(t *testing.T, e env) { + te := newTest(t, e) + b := &testBalancer{} + balancer.Register(b) + te.customDialOptions = []grpc.DialOption{ + grpc.WithBalancerName(testBalancerName), + } + te.userAgent = failAppUA + te.startServer(&testServer{security: e.security}) + defer te.tearDown() + + cc := te.clientConn() + tc := testpb.NewTestServiceClient(cc) + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + wantErr := detailedError + if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); !reflect.DeepEqual(err, wantErr) { + t.Fatalf("TestService/EmptyCall(_, _) = _, %v, want _, %v", err, wantErr) + } + md := metadata.Pairs("testMDKey", "testMDVal") + ctx = metadata.NewOutgoingContext(ctx, md) + if _, err := tc.UnaryCall(ctx, &testpb.SimpleRequest{}); err != nil { + t.Fatalf("TestService.UnaryCall(%v, _, _, _) = _, %v; want _, ", ctx, err) + } + + poWant := []balancer.PickOptions{ + {FullMethodName: "/grpc.testing.TestService/EmptyCall"}, + {FullMethodName: "/grpc.testing.TestService/UnaryCall", Header: md}, + } + if !reflect.DeepEqual(b.pickOptions, poWant) { + t.Fatalf("b.pickOptions = %v; want %v", b.pickOptions, poWant) + } + + if len(b.doneInfo) < 1 || !reflect.DeepEqual(b.doneInfo[0].Err, wantErr) { + t.Fatalf("b.doneInfo = %v; want b.doneInfo[0].Err = %v", b.doneInfo, wantErr) + } + if len(b.doneInfo) < 2 || !reflect.DeepEqual(b.doneInfo[1].Trailer, testTrailerMetadata) { + t.Fatalf("b.doneInfo = %v; want b.doneInfo[1].Trailer = %v", b.doneInfo, testTrailerMetadata) + } +} diff --git a/vendor/google.golang.org/grpc/test/channelz_linux_go110_test.go b/vendor/google.golang.org/grpc/test/channelz_linux_go110_test.go new file mode 100644 index 0000000000000000000000000000000000000000..31ce11dbc0e1e046b69511ae42e32d5d24293b7b --- /dev/null +++ b/vendor/google.golang.org/grpc/test/channelz_linux_go110_test.go @@ -0,0 +1,100 @@ +// +build go1.10,linux,!appengine + +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// The test in this file should be run in an environment that has go1.10 or later, +// as the function SyscallConn() (required to get socket option) was +// introduced to net.TCPListener in go1.10. + +package test + +import ( + "testing" + "time" + + "google.golang.org/grpc/internal/channelz" + "google.golang.org/grpc/internal/leakcheck" + testpb "google.golang.org/grpc/test/grpc_testing" +) + +func TestCZSocketMetricsSocketOption(t *testing.T) { + envs := []env{tcpClearRREnv, tcpTLSRREnv} + for _, e := range envs { + testCZSocketMetricsSocketOption(t, e) + } +} + +func testCZSocketMetricsSocketOption(t *testing.T, e env) { + defer leakcheck.Check(t) + channelz.NewChannelzStorage() + te := newTest(t, e) + te.startServer(&testServer{security: e.security}) + defer te.tearDown() + cc := te.clientConn() + tc := testpb.NewTestServiceClient(cc) + doSuccessfulUnaryCall(tc, t) + + time.Sleep(10 * time.Millisecond) + ss, _ := channelz.GetServers(0) + if len(ss) != 1 { + t.Fatalf("There should be one server, not %d", len(ss)) + } + if len(ss[0].ListenSockets) != 1 { + t.Fatalf("There should be one listen socket, not %d", len(ss[0].ListenSockets)) + } + for id := range ss[0].ListenSockets { + sm := channelz.GetSocket(id) + if sm == nil || sm.SocketData == nil || sm.SocketData.SocketOptions == nil { + t.Fatalf("Unable to get server listen socket options") + } + } + ns, _ := channelz.GetServerSockets(ss[0].ID, 0) + if len(ns) != 1 { + t.Fatalf("There should be one server normal socket, not %d", len(ns)) + } + if ns[0] == nil || ns[0].SocketData == nil || ns[0].SocketData.SocketOptions == nil { + t.Fatalf("Unable to get server normal socket options") + } + + tchan, _ := channelz.GetTopChannels(0) + if len(tchan) != 1 { + t.Fatalf("There should only be one top channel, not %d", len(tchan)) + } + if len(tchan[0].SubChans) != 1 { + t.Fatalf("There should only be one subchannel under top channel %d, not %d", tchan[0].ID, len(tchan[0].SubChans)) + } + var id int64 + for id = range tchan[0].SubChans { + break + } + sc := channelz.GetSubChannel(id) + if sc == nil { + t.Fatalf("There should only be one socket under subchannel %d, not 0", id) + } + if len(sc.Sockets) != 1 { + t.Fatalf("There should only be one socket under subchannel %d, not %d", sc.ID, len(sc.Sockets)) + } + for id = range sc.Sockets { + break + } + skt := channelz.GetSocket(id) + if skt == nil || skt.SocketData == nil || skt.SocketData.SocketOptions == nil { + t.Fatalf("Unable to get client normal socket options") + } +} diff --git a/vendor/google.golang.org/grpc/test/channelz_test.go b/vendor/google.golang.org/grpc/test/channelz_test.go index eaa657c4b6a04063ce06b8d3b94a6b5503e9f7d2..9a5abfe6a8f205cc5a7c08d57ad5aad2e1b359d2 100644 --- a/vendor/google.golang.org/grpc/test/channelz_test.go +++ b/vendor/google.golang.org/grpc/test/channelz_test.go @@ -19,17 +19,22 @@ package test import ( + "context" + "crypto/tls" "fmt" "net" + "reflect" "sync" "testing" "time" - "golang.org/x/net/context" "golang.org/x/net/http2" "google.golang.org/grpc" _ "google.golang.org/grpc/balancer/grpclb" + "google.golang.org/grpc/balancer/roundrobin" "google.golang.org/grpc/codes" + "google.golang.org/grpc/connectivity" + "google.golang.org/grpc/credentials" "google.golang.org/grpc/internal/channelz" "google.golang.org/grpc/internal/leakcheck" "google.golang.org/grpc/keepalive" @@ -37,16 +42,13 @@ import ( "google.golang.org/grpc/resolver/manual" "google.golang.org/grpc/status" testpb "google.golang.org/grpc/test/grpc_testing" + "google.golang.org/grpc/testdata" ) -func init() { - channelz.TurnOn() -} - func (te *test) startServers(ts testpb.TestServiceServer, num int) { for i := 0; i < num; i++ { te.startServer(ts) - te.srvs = append(te.srvs, te.srv) + te.srvs = append(te.srvs, te.srv.(*grpc.Server)) te.srvAddrs = append(te.srvAddrs, te.srvAddr) te.srv = nil te.srvAddr = "" @@ -125,7 +127,7 @@ func TestCZTopChannelRegistrationAndDeletion(t *testing.T) { } if err := verifyResultWithDelay(func() (bool, error) { if tcs, end := channelz.GetTopChannels(c.start); len(tcs) != c.length || end != c.end { - return false, fmt.Errorf("GetTopChannels(%d) = %+v (len of which: %d), end: %+v, want len(GetTopChannels(%d)) = %d, end: %+v", c.start, tcs, len(tcs), end, c.start, c.length, c.end) + return false, fmt.Errorf("getTopChannels(%d) = %+v (len of which: %d), end: %+v, want len(GetTopChannels(%d)) = %d, end: %+v", c.start, tcs, len(tcs), end, c.start, c.length, c.end) } return true, nil }); err != nil { @@ -138,7 +140,7 @@ func TestCZTopChannelRegistrationAndDeletion(t *testing.T) { if err := verifyResultWithDelay(func() (bool, error) { if tcs, end := channelz.GetTopChannels(c.start); len(tcs) != 0 || !end { - return false, fmt.Errorf("GetTopChannels(0) = %+v (len of which: %d), end: %+v, want len(GetTopChannels(0)) = 0, end: true", tcs, len(tcs), end) + return false, fmt.Errorf("getTopChannels(0) = %+v (len of which: %d), end: %+v, want len(GetTopChannels(0)) = 0, end: true", tcs, len(tcs), end) } return true, nil }); err != nil { @@ -166,10 +168,10 @@ func TestCZNestedChannelRegistrationAndDeletion(t *testing.T) { if err := verifyResultWithDelay(func() (bool, error) { tcs, _ := channelz.GetTopChannels(0) if len(tcs) != 1 { - return false, fmt.Errorf("There should only be one top channel, not %d", len(tcs)) + return false, fmt.Errorf("there should only be one top channel, not %d", len(tcs)) } if len(tcs[0].NestedChans) != 1 { - return false, fmt.Errorf("There should be one nested channel from grpclb, not %d", len(tcs[0].NestedChans)) + return false, fmt.Errorf("there should be one nested channel from grpclb, not %d", len(tcs[0].NestedChans)) } return true, nil }); err != nil { @@ -183,10 +185,10 @@ func TestCZNestedChannelRegistrationAndDeletion(t *testing.T) { if err := verifyResultWithDelay(func() (bool, error) { tcs, _ := channelz.GetTopChannels(0) if len(tcs) != 1 { - return false, fmt.Errorf("There should only be one top channel, not %d", len(tcs)) + return false, fmt.Errorf("there should only be one top channel, not %d", len(tcs)) } if len(tcs[0].NestedChans) != 0 { - return false, fmt.Errorf("There should be 0 nested channel from grpclb, not %d", len(tcs[0].NestedChans)) + return false, fmt.Errorf("there should be 0 nested channel from grpclb, not %d", len(tcs[0].NestedChans)) } return true, nil }); err != nil { @@ -216,10 +218,10 @@ func TestCZClientSubChannelSocketRegistrationAndDeletion(t *testing.T) { if err := verifyResultWithDelay(func() (bool, error) { tcs, _ := channelz.GetTopChannels(0) if len(tcs) != 1 { - return false, fmt.Errorf("There should only be one top channel, not %d", len(tcs)) + return false, fmt.Errorf("there should only be one top channel, not %d", len(tcs)) } if len(tcs[0].SubChans) != num { - return false, fmt.Errorf("There should be %d subchannel not %d", num, len(tcs[0].SubChans)) + return false, fmt.Errorf("there should be %d subchannel not %d", num, len(tcs[0].SubChans)) } count := 0 for k := range tcs[0].SubChans { @@ -230,7 +232,7 @@ func TestCZClientSubChannelSocketRegistrationAndDeletion(t *testing.T) { count += len(sc.Sockets) } if count != num { - return false, fmt.Errorf("There should be %d sockets not %d", num, count) + return false, fmt.Errorf("there should be %d sockets not %d", num, count) } return true, nil @@ -243,10 +245,10 @@ func TestCZClientSubChannelSocketRegistrationAndDeletion(t *testing.T) { if err := verifyResultWithDelay(func() (bool, error) { tcs, _ := channelz.GetTopChannels(0) if len(tcs) != 1 { - return false, fmt.Errorf("There should only be one top channel, not %d", len(tcs)) + return false, fmt.Errorf("there should only be one top channel, not %d", len(tcs)) } if len(tcs[0].SubChans) != num-1 { - return false, fmt.Errorf("There should be %d subchannel not %d", num-1, len(tcs[0].SubChans)) + return false, fmt.Errorf("there should be %d subchannel not %d", num-1, len(tcs[0].SubChans)) } count := 0 for k := range tcs[0].SubChans { @@ -257,7 +259,7 @@ func TestCZClientSubChannelSocketRegistrationAndDeletion(t *testing.T) { count += len(sc.Sockets) } if count != num-1 { - return false, fmt.Errorf("There should be %d sockets not %d", num-1, count) + return false, fmt.Errorf("there should be %d sockets not %d", num-1, count) } return true, nil @@ -289,14 +291,14 @@ func TestCZServerSocketRegistrationAndDeletion(t *testing.T) { if err := verifyResultWithDelay(func() (bool, error) { ss, _ := channelz.GetServers(0) if len(ss) != 1 { - return false, fmt.Errorf("There should only be one server, not %d", len(ss)) + return false, fmt.Errorf("there should only be one server, not %d", len(ss)) } if len(ss[0].ListenSockets) != 1 { - return false, fmt.Errorf("There should only be one server listen socket, not %d", len(ss[0].ListenSockets)) + return false, fmt.Errorf("there should only be one server listen socket, not %d", len(ss[0].ListenSockets)) } ns, _ := channelz.GetServerSockets(ss[0].ID, 0) if len(ns) != num { - return false, fmt.Errorf("There should be %d normal sockets not %d", num, len(ns)) + return false, fmt.Errorf("there should be %d normal sockets not %d", num, len(ns)) } svrID = ss[0].ID return true, nil @@ -309,7 +311,7 @@ func TestCZServerSocketRegistrationAndDeletion(t *testing.T) { if err := verifyResultWithDelay(func() (bool, error) { ns, _ := channelz.GetServerSockets(svrID, 0) if len(ns) != num-1 { - return false, fmt.Errorf("There should be %d normal sockets not %d", num-1, len(ns)) + return false, fmt.Errorf("there should be %d normal sockets not %d", num-1, len(ns)) } return true, nil }); err != nil { @@ -329,10 +331,10 @@ func TestCZServerListenSocketDeletion(t *testing.T) { if err := verifyResultWithDelay(func() (bool, error) { ss, _ := channelz.GetServers(0) if len(ss) != 1 { - return false, fmt.Errorf("There should only be one server, not %d", len(ss)) + return false, fmt.Errorf("there should only be one server, not %d", len(ss)) } if len(ss[0].ListenSockets) != 1 { - return false, fmt.Errorf("There should only be one server listen socket, not %d", len(ss[0].ListenSockets)) + return false, fmt.Errorf("there should only be one server listen socket, not %d", len(ss[0].ListenSockets)) } return true, nil }); err != nil { @@ -343,7 +345,7 @@ func TestCZServerListenSocketDeletion(t *testing.T) { if err := verifyResultWithDelay(func() (bool, error) { ss, _ := channelz.GetServers(0) if len(ss) != 1 { - return false, fmt.Errorf("There should be 1 server, not %d", len(ss)) + return false, fmt.Errorf("there should be 1 server, not %d", len(ss)) } return true, nil }); err != nil { @@ -465,10 +467,10 @@ func TestCZChannelMetrics(t *testing.T) { if err := verifyResultWithDelay(func() (bool, error) { tcs, _ := channelz.GetTopChannels(0) if len(tcs) != 1 { - return false, fmt.Errorf("There should only be one top channel, not %d", len(tcs)) + return false, fmt.Errorf("there should only be one top channel, not %d", len(tcs)) } if len(tcs[0].SubChans) != num { - return false, fmt.Errorf("There should be %d subchannel not %d", num, len(tcs[0].SubChans)) + return false, fmt.Errorf("there should be %d subchannel not %d", num, len(tcs[0].SubChans)) } var cst, csu, cf int64 for k := range tcs[0].SubChans { @@ -481,22 +483,22 @@ func TestCZChannelMetrics(t *testing.T) { cf += sc.ChannelData.CallsFailed } if cst != 3 { - return false, fmt.Errorf("There should be 3 CallsStarted not %d", cst) + return false, fmt.Errorf("there should be 3 CallsStarted not %d", cst) } if csu != 1 { - return false, fmt.Errorf("There should be 1 CallsSucceeded not %d", csu) + return false, fmt.Errorf("there should be 1 CallsSucceeded not %d", csu) } if cf != 1 { - return false, fmt.Errorf("There should be 1 CallsFailed not %d", cf) + return false, fmt.Errorf("there should be 1 CallsFailed not %d", cf) } if tcs[0].ChannelData.CallsStarted != 3 { - return false, fmt.Errorf("There should be 3 CallsStarted not %d", tcs[0].ChannelData.CallsStarted) + return false, fmt.Errorf("there should be 3 CallsStarted not %d", tcs[0].ChannelData.CallsStarted) } if tcs[0].ChannelData.CallsSucceeded != 1 { - return false, fmt.Errorf("There should be 1 CallsSucceeded not %d", tcs[0].ChannelData.CallsSucceeded) + return false, fmt.Errorf("there should be 1 CallsSucceeded not %d", tcs[0].ChannelData.CallsSucceeded) } if tcs[0].ChannelData.CallsFailed != 1 { - return false, fmt.Errorf("There should be 1 CallsFailed not %d", tcs[0].ChannelData.CallsFailed) + return false, fmt.Errorf("there should be 1 CallsFailed not %d", tcs[0].ChannelData.CallsFailed) } return true, nil }); err != nil { @@ -543,16 +545,16 @@ func TestCZServerMetrics(t *testing.T) { if err := verifyResultWithDelay(func() (bool, error) { ss, _ := channelz.GetServers(0) if len(ss) != 1 { - return false, fmt.Errorf("There should only be one server, not %d", len(ss)) + return false, fmt.Errorf("there should only be one server, not %d", len(ss)) } if ss[0].ServerData.CallsStarted != 3 { - return false, fmt.Errorf("There should be 3 CallsStarted not %d", ss[0].ServerData.CallsStarted) + return false, fmt.Errorf("there should be 3 CallsStarted not %d", ss[0].ServerData.CallsStarted) } if ss[0].ServerData.CallsSucceeded != 1 { - return false, fmt.Errorf("There should be 1 CallsSucceeded not %d", ss[0].ServerData.CallsSucceeded) + return false, fmt.Errorf("there should be 1 CallsSucceeded not %d", ss[0].ServerData.CallsSucceeded) } if ss[0].ServerData.CallsFailed != 1 { - return false, fmt.Errorf("There should be 1 CallsFailed not %d", ss[0].ServerData.CallsFailed) + return false, fmt.Errorf("there should be 1 CallsFailed not %d", ss[0].ServerData.CallsFailed) } return true, nil }); err != nil { @@ -806,10 +808,10 @@ func TestCZClientSocketMetricsStreamsAndMessagesCount(t *testing.T) { if err := verifyResultWithDelay(func() (bool, error) { tchan, _ := channelz.GetTopChannels(0) if len(tchan) != 1 { - return false, fmt.Errorf("There should only be one top channel, not %d", len(tchan)) + return false, fmt.Errorf("there should only be one top channel, not %d", len(tchan)) } if len(tchan[0].SubChans) != 1 { - return false, fmt.Errorf("There should only be one subchannel under top channel %d, not %d", tchan[0].ID, len(tchan[0].SubChans)) + return false, fmt.Errorf("there should only be one subchannel under top channel %d, not %d", tchan[0].ID, len(tchan[0].SubChans)) } for scID = range tchan[0].SubChans { @@ -817,10 +819,10 @@ func TestCZClientSocketMetricsStreamsAndMessagesCount(t *testing.T) { } sc := channelz.GetSubChannel(scID) if sc == nil { - return false, fmt.Errorf("There should only be one socket under subchannel %d, not 0", scID) + return false, fmt.Errorf("there should only be one socket under subchannel %d, not 0", scID) } if len(sc.Sockets) != 1 { - return false, fmt.Errorf("There should only be one socket under subchannel %d, not %d", sc.ID, len(sc.Sockets)) + return false, fmt.Errorf("there should only be one socket under subchannel %d, not %d", sc.ID, len(sc.Sockets)) } for skID = range sc.Sockets { break @@ -907,10 +909,10 @@ func TestCZClientAndServerSocketMetricsStreamsCountFlowControlRSTStream(t *testi if err := verifyResultWithDelay(func() (bool, error) { tchan, _ := channelz.GetTopChannels(0) if len(tchan) != 1 { - return false, fmt.Errorf("There should only be one top channel, not %d", len(tchan)) + return false, fmt.Errorf("there should only be one top channel, not %d", len(tchan)) } if len(tchan[0].SubChans) != 1 { - return false, fmt.Errorf("There should only be one subchannel under top channel %d, not %d", tchan[0].ID, len(tchan[0].SubChans)) + return false, fmt.Errorf("there should only be one subchannel under top channel %d, not %d", tchan[0].ID, len(tchan[0].SubChans)) } var id int64 for id = range tchan[0].SubChans { @@ -918,10 +920,10 @@ func TestCZClientAndServerSocketMetricsStreamsCountFlowControlRSTStream(t *testi } sc := channelz.GetSubChannel(id) if sc == nil { - return false, fmt.Errorf("There should only be one socket under subchannel %d, not 0", id) + return false, fmt.Errorf("there should only be one socket under subchannel %d, not 0", id) } if len(sc.Sockets) != 1 { - return false, fmt.Errorf("There should only be one socket under subchannel %d, not %d", sc.ID, len(sc.Sockets)) + return false, fmt.Errorf("there should only be one socket under subchannel %d, not %d", sc.ID, len(sc.Sockets)) } for id = range sc.Sockets { break @@ -933,16 +935,16 @@ func TestCZClientAndServerSocketMetricsStreamsCountFlowControlRSTStream(t *testi } ss, _ := channelz.GetServers(0) if len(ss) != 1 { - return false, fmt.Errorf("There should only be one server, not %d", len(ss)) + return false, fmt.Errorf("there should only be one server, not %d", len(ss)) } ns, _ := channelz.GetServerSockets(ss[0].ID, 0) if len(ns) != 1 { - return false, fmt.Errorf("There should be one server normal socket, not %d", len(ns)) + return false, fmt.Errorf("there should be one server normal socket, not %d", len(ns)) } sktData = ns[0].SocketData if sktData.StreamsStarted != 1 || sktData.StreamsSucceeded != 0 || sktData.StreamsFailed != 1 { - return false, fmt.Errorf("Server socket metric with ID %d, want (StreamsStarted, StreamsSucceeded, StreamsFailed) = (1, 0, 1), got (%d, %d, %d)", ns[0].ID, sktData.StreamsStarted, sktData.StreamsSucceeded, sktData.StreamsFailed) + return false, fmt.Errorf("server socket metric with ID %d, want (StreamsStarted, StreamsSucceeded, StreamsFailed) = (1, 0, 1), got (%d, %d, %d)", ns[0].ID, sktData.StreamsStarted, sktData.StreamsSucceeded, sktData.StreamsFailed) } return true, nil }); err != nil { @@ -973,10 +975,10 @@ func TestCZClientAndServerSocketMetricsFlowControl(t *testing.T) { if err := verifyResultWithDelay(func() (bool, error) { tchan, _ := channelz.GetTopChannels(0) if len(tchan) != 1 { - return false, fmt.Errorf("There should only be one top channel, not %d", len(tchan)) + return false, fmt.Errorf("there should only be one top channel, not %d", len(tchan)) } if len(tchan[0].SubChans) != 1 { - return false, fmt.Errorf("There should only be one subchannel under top channel %d, not %d", tchan[0].ID, len(tchan[0].SubChans)) + return false, fmt.Errorf("there should only be one subchannel under top channel %d, not %d", tchan[0].ID, len(tchan[0].SubChans)) } var id int64 for id = range tchan[0].SubChans { @@ -984,10 +986,10 @@ func TestCZClientAndServerSocketMetricsFlowControl(t *testing.T) { } sc := channelz.GetSubChannel(id) if sc == nil { - return false, fmt.Errorf("There should only be one socket under subchannel %d, not 0", id) + return false, fmt.Errorf("there should only be one socket under subchannel %d, not 0", id) } if len(sc.Sockets) != 1 { - return false, fmt.Errorf("There should only be one socket under subchannel %d, not %d", sc.ID, len(sc.Sockets)) + return false, fmt.Errorf("there should only be one socket under subchannel %d, not %d", sc.ID, len(sc.Sockets)) } for id = range sc.Sockets { break @@ -996,16 +998,16 @@ func TestCZClientAndServerSocketMetricsFlowControl(t *testing.T) { sktData := skt.SocketData // 65536 - 5 (Length-Prefixed-Message size) * 10 = 65486 if sktData.LocalFlowControlWindow != 65486 || sktData.RemoteFlowControlWindow != 65486 { - return false, fmt.Errorf("Client: (LocalFlowControlWindow, RemoteFlowControlWindow) size should be (65536, 65486), not (%d, %d)", sktData.LocalFlowControlWindow, sktData.RemoteFlowControlWindow) + return false, fmt.Errorf("client: (LocalFlowControlWindow, RemoteFlowControlWindow) size should be (65536, 65486), not (%d, %d)", sktData.LocalFlowControlWindow, sktData.RemoteFlowControlWindow) } ss, _ := channelz.GetServers(0) if len(ss) != 1 { - return false, fmt.Errorf("There should only be one server, not %d", len(ss)) + return false, fmt.Errorf("there should only be one server, not %d", len(ss)) } ns, _ := channelz.GetServerSockets(ss[0].ID, 0) sktData = ns[0].SocketData if sktData.LocalFlowControlWindow != 65486 || sktData.RemoteFlowControlWindow != 65486 { - return false, fmt.Errorf("Server: (LocalFlowControlWindow, RemoteFlowControlWindow) size should be (65536, 65486), not (%d, %d)", sktData.LocalFlowControlWindow, sktData.RemoteFlowControlWindow) + return false, fmt.Errorf("server: (LocalFlowControlWindow, RemoteFlowControlWindow) size should be (65536, 65486), not (%d, %d)", sktData.LocalFlowControlWindow, sktData.RemoteFlowControlWindow) } cliSktID, svrSktID = id, ss[0].ID return true, nil @@ -1021,16 +1023,16 @@ func TestCZClientAndServerSocketMetricsFlowControl(t *testing.T) { // Local: 65536 - 5 (Length-Prefixed-Message size) * 10 = 65486 // Remote: 65536 - 5 (Length-Prefixed-Message size) * 10 - 10011 = 55475 if sktData.LocalFlowControlWindow != 65486 || sktData.RemoteFlowControlWindow != 55475 { - return false, fmt.Errorf("Client: (LocalFlowControlWindow, RemoteFlowControlWindow) size should be (65486, 55475), not (%d, %d)", sktData.LocalFlowControlWindow, sktData.RemoteFlowControlWindow) + return false, fmt.Errorf("client: (LocalFlowControlWindow, RemoteFlowControlWindow) size should be (65486, 55475), not (%d, %d)", sktData.LocalFlowControlWindow, sktData.RemoteFlowControlWindow) } ss, _ := channelz.GetServers(0) if len(ss) != 1 { - return false, fmt.Errorf("There should only be one server, not %d", len(ss)) + return false, fmt.Errorf("there should only be one server, not %d", len(ss)) } ns, _ := channelz.GetServerSockets(svrSktID, 0) sktData = ns[0].SocketData if sktData.LocalFlowControlWindow != 55475 || sktData.RemoteFlowControlWindow != 65486 { - return false, fmt.Errorf("Server: (LocalFlowControlWindow, RemoteFlowControlWindow) size should be (55475, 65486), not (%d, %d)", sktData.LocalFlowControlWindow, sktData.RemoteFlowControlWindow) + return false, fmt.Errorf("server: (LocalFlowControlWindow, RemoteFlowControlWindow) size should be (55475, 65486), not (%d, %d)", sktData.LocalFlowControlWindow, sktData.RemoteFlowControlWindow) } return true, nil }); err != nil { @@ -1046,16 +1048,16 @@ func TestCZClientAndServerSocketMetricsFlowControl(t *testing.T) { // Local: 65536 - 5 (Length-Prefixed-Message size) * 10 = 65486 // Remote: 65536 if sktData.LocalFlowControlWindow != 65486 || sktData.RemoteFlowControlWindow != 65536 { - return false, fmt.Errorf("Client: (LocalFlowControlWindow, RemoteFlowControlWindow) size should be (65486, 65536), not (%d, %d)", sktData.LocalFlowControlWindow, sktData.RemoteFlowControlWindow) + return false, fmt.Errorf("client: (LocalFlowControlWindow, RemoteFlowControlWindow) size should be (65486, 65536), not (%d, %d)", sktData.LocalFlowControlWindow, sktData.RemoteFlowControlWindow) } ss, _ := channelz.GetServers(0) if len(ss) != 1 { - return false, fmt.Errorf("There should only be one server, not %d", len(ss)) + return false, fmt.Errorf("there should only be one server, not %d", len(ss)) } ns, _ := channelz.GetServerSockets(svrSktID, 0) sktData = ns[0].SocketData if sktData.LocalFlowControlWindow != 65536 || sktData.RemoteFlowControlWindow != 65486 { - return false, fmt.Errorf("Server: (LocalFlowControlWindow, RemoteFlowControlWindow) size should be (65536, 65486), not (%d, %d)", sktData.LocalFlowControlWindow, sktData.RemoteFlowControlWindow) + return false, fmt.Errorf("server: (LocalFlowControlWindow, RemoteFlowControlWindow) size should be (65536, 65486), not (%d, %d)", sktData.LocalFlowControlWindow, sktData.RemoteFlowControlWindow) } return true, nil }); err != nil { @@ -1078,10 +1080,10 @@ func TestCZClientSocketMetricsKeepAlive(t *testing.T) { if err := verifyResultWithDelay(func() (bool, error) { tchan, _ := channelz.GetTopChannels(0) if len(tchan) != 1 { - return false, fmt.Errorf("There should only be one top channel, not %d", len(tchan)) + return false, fmt.Errorf("there should only be one top channel, not %d", len(tchan)) } if len(tchan[0].SubChans) != 1 { - return false, fmt.Errorf("There should only be one subchannel under top channel %d, not %d", tchan[0].ID, len(tchan[0].SubChans)) + return false, fmt.Errorf("there should only be one subchannel under top channel %d, not %d", tchan[0].ID, len(tchan[0].SubChans)) } var id int64 for id = range tchan[0].SubChans { @@ -1089,17 +1091,17 @@ func TestCZClientSocketMetricsKeepAlive(t *testing.T) { } sc := channelz.GetSubChannel(id) if sc == nil { - return false, fmt.Errorf("There should only be one socket under subchannel %d, not 0", id) + return false, fmt.Errorf("there should only be one socket under subchannel %d, not 0", id) } if len(sc.Sockets) != 1 { - return false, fmt.Errorf("There should only be one socket under subchannel %d, not %d", sc.ID, len(sc.Sockets)) + return false, fmt.Errorf("there should only be one socket under subchannel %d, not %d", sc.ID, len(sc.Sockets)) } for id = range sc.Sockets { break } skt := channelz.GetSocket(id) if skt.SocketData.KeepAlivesSent != 2 { // doIdleCallToInvokeKeepAlive func is set up to send 2 KeepAlives. - return false, fmt.Errorf("There should be 2 KeepAlives sent, not %d", skt.SocketData.KeepAlivesSent) + return false, fmt.Errorf("there should be 2 KeepAlives sent, not %d", skt.SocketData.KeepAlivesSent) } return true, nil }); err != nil { @@ -1123,7 +1125,7 @@ func TestCZServerSocketMetricsStreamsAndMessagesCount(t *testing.T) { if err := verifyResultWithDelay(func() (bool, error) { ss, _ := channelz.GetServers(0) if len(ss) != 1 { - return false, fmt.Errorf("There should only be one server, not %d", len(ss)) + return false, fmt.Errorf("there should only be one server, not %d", len(ss)) } svrID = ss[0].ID return true, nil @@ -1136,7 +1138,7 @@ func TestCZServerSocketMetricsStreamsAndMessagesCount(t *testing.T) { ns, _ := channelz.GetServerSockets(svrID, 0) sktData := ns[0].SocketData if sktData.StreamsStarted != 1 || sktData.StreamsSucceeded != 1 || sktData.StreamsFailed != 0 || sktData.MessagesSent != 1 || sktData.MessagesReceived != 1 { - return false, fmt.Errorf("Server socket metric with ID %d, want (StreamsStarted, StreamsSucceeded, MessagesSent, MessagesReceived) = (1, 1, 1, 1), got (%d, %d, %d, %d, %d)", ns[0].ID, sktData.StreamsStarted, sktData.StreamsSucceeded, sktData.StreamsFailed, sktData.MessagesSent, sktData.MessagesReceived) + return false, fmt.Errorf("server socket metric with ID %d, want (StreamsStarted, StreamsSucceeded, MessagesSent, MessagesReceived) = (1, 1, 1, 1), got (%d, %d, %d, %d, %d)", ns[0].ID, sktData.StreamsStarted, sktData.StreamsSucceeded, sktData.StreamsFailed, sktData.MessagesSent, sktData.MessagesReceived) } return true, nil }); err != nil { @@ -1148,7 +1150,7 @@ func TestCZServerSocketMetricsStreamsAndMessagesCount(t *testing.T) { ns, _ := channelz.GetServerSockets(svrID, 0) sktData := ns[0].SocketData if sktData.StreamsStarted != 2 || sktData.StreamsSucceeded != 2 || sktData.StreamsFailed != 0 || sktData.MessagesSent != 1 || sktData.MessagesReceived != 1 { - return false, fmt.Errorf("Server socket metric with ID %d, want (StreamsStarted, StreamsSucceeded, StreamsFailed, MessagesSent, MessagesReceived) = (2, 2, 0, 1, 1), got (%d, %d, %d, %d, %d)", ns[0].ID, sktData.StreamsStarted, sktData.StreamsSucceeded, sktData.StreamsFailed, sktData.MessagesSent, sktData.MessagesReceived) + return false, fmt.Errorf("server socket metric with ID %d, want (StreamsStarted, StreamsSucceeded, StreamsFailed, MessagesSent, MessagesReceived) = (2, 2, 0, 1, 1), got (%d, %d, %d, %d, %d)", ns[0].ID, sktData.StreamsStarted, sktData.StreamsSucceeded, sktData.StreamsFailed, sktData.MessagesSent, sktData.MessagesReceived) } return true, nil }); err != nil { @@ -1160,7 +1162,7 @@ func TestCZServerSocketMetricsStreamsAndMessagesCount(t *testing.T) { ns, _ := channelz.GetServerSockets(svrID, 0) sktData := ns[0].SocketData if sktData.StreamsStarted != 3 || sktData.StreamsSucceeded != 2 || sktData.StreamsFailed != 1 || sktData.MessagesSent != 2 || sktData.MessagesReceived != 2 { - return false, fmt.Errorf("Server socket metric with ID %d, want (StreamsStarted, StreamsSucceeded, StreamsFailed, MessagesSent, MessagesReceived) = (3, 2, 1, 2, 2), got (%d, %d, %d, %d, %d)", ns[0].ID, sktData.StreamsStarted, sktData.StreamsSucceeded, sktData.StreamsFailed, sktData.MessagesSent, sktData.MessagesReceived) + return false, fmt.Errorf("server socket metric with ID %d, want (StreamsStarted, StreamsSucceeded, StreamsFailed, MessagesSent, MessagesReceived) = (3, 2, 1, 2, 2), got (%d, %d, %d, %d, %d)", ns[0].ID, sktData.StreamsStarted, sktData.StreamsSucceeded, sktData.StreamsFailed, sktData.MessagesSent, sktData.MessagesReceived) } return true, nil }); err != nil { @@ -1183,14 +1185,728 @@ func TestCZServerSocketMetricsKeepAlive(t *testing.T) { if err := verifyResultWithDelay(func() (bool, error) { ss, _ := channelz.GetServers(0) if len(ss) != 1 { - return false, fmt.Errorf("There should be one server, not %d", len(ss)) + return false, fmt.Errorf("there should be one server, not %d", len(ss)) } ns, _ := channelz.GetServerSockets(ss[0].ID, 0) if len(ns) != 1 { - return false, fmt.Errorf("There should be one server normal socket, not %d", len(ns)) + return false, fmt.Errorf("there should be one server normal socket, not %d", len(ns)) } if ns[0].SocketData.KeepAlivesSent != 2 { // doIdleCallToInvokeKeepAlive func is set up to send 2 KeepAlives. - return false, fmt.Errorf("There should be 2 KeepAlives sent, not %d", ns[0].SocketData.KeepAlivesSent) + return false, fmt.Errorf("there should be 2 KeepAlives sent, not %d", ns[0].SocketData.KeepAlivesSent) + } + return true, nil + }); err != nil { + t.Fatal(err) + } +} + +var cipherSuites = []string{ + "TLS_RSA_WITH_RC4_128_SHA", + "TLS_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_RSA_WITH_AES_128_CBC_SHA", + "TLS_RSA_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_RC4_128_SHA", + "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_FALLBACK_SCSV", + "TLS_RSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", +} + +func TestCZSocketGetSecurityValueTLS(t *testing.T) { + defer leakcheck.Check(t) + channelz.NewChannelzStorage() + e := tcpTLSRREnv + te := newTest(t, e) + te.startServer(&testServer{security: e.security}) + defer te.tearDown() + te.clientConn() + if err := verifyResultWithDelay(func() (bool, error) { + tchan, _ := channelz.GetTopChannels(0) + if len(tchan) != 1 { + return false, fmt.Errorf("there should only be one top channel, not %d", len(tchan)) + } + if len(tchan[0].SubChans) != 1 { + return false, fmt.Errorf("there should only be one subchannel under top channel %d, not %d", tchan[0].ID, len(tchan[0].SubChans)) + } + var id int64 + for id = range tchan[0].SubChans { + break + } + sc := channelz.GetSubChannel(id) + if sc == nil { + return false, fmt.Errorf("there should only be one socket under subchannel %d, not 0", id) + } + if len(sc.Sockets) != 1 { + return false, fmt.Errorf("there should only be one socket under subchannel %d, not %d", sc.ID, len(sc.Sockets)) + } + for id = range sc.Sockets { + break + } + skt := channelz.GetSocket(id) + cert, _ := tls.LoadX509KeyPair(testdata.Path("server1.pem"), testdata.Path("server1.key")) + securityVal, ok := skt.SocketData.Security.(*credentials.TLSChannelzSecurityValue) + if !ok { + return false, fmt.Errorf("the SocketData.Security is of type: %T, want: *credentials.TLSChannelzSecurityValue", skt.SocketData.Security) + } + if !reflect.DeepEqual(securityVal.RemoteCertificate, cert.Certificate[0]) { + return false, fmt.Errorf("SocketData.Security.RemoteCertificate got: %v, want: %v", securityVal.RemoteCertificate, cert.Certificate[0]) + } + for _, v := range cipherSuites { + if v == securityVal.StandardName { + return true, nil + } + } + return false, fmt.Errorf("SocketData.Security.StandardName got: %v, want it to be one of %v ", securityVal.StandardName, cipherSuites) + }); err != nil { + t.Fatal(err) + } +} + +func TestCZChannelTraceCreationDeletion(t *testing.T) { + defer leakcheck.Check(t) + channelz.NewChannelzStorage() + e := tcpClearRREnv + // avoid calling API to set balancer type, which will void service config's change of balancer. + e.balancer = "" + te := newTest(t, e) + r, cleanup := manual.GenerateAndRegisterManualResolver() + defer cleanup() + resolvedAddrs := []resolver.Address{{Addr: "127.0.0.1:0", Type: resolver.GRPCLB, ServerName: "grpclb.server"}} + r.InitialAddrs(resolvedAddrs) + te.resolverScheme = r.Scheme() + te.clientConn() + defer te.tearDown() + var nestedConn int64 + if err := verifyResultWithDelay(func() (bool, error) { + tcs, _ := channelz.GetTopChannels(0) + if len(tcs) != 1 { + return false, fmt.Errorf("there should only be one top channel, not %d", len(tcs)) + } + if len(tcs[0].NestedChans) != 1 { + return false, fmt.Errorf("there should be one nested channel from grpclb, not %d", len(tcs[0].NestedChans)) + } + for k := range tcs[0].NestedChans { + nestedConn = k + } + for _, e := range tcs[0].Trace.Events { + if e.RefID == nestedConn && e.RefType != channelz.RefChannel { + return false, fmt.Errorf("nested channel trace event shoud have RefChannel as RefType") + } + } + ncm := channelz.GetChannel(nestedConn) + if ncm.Trace == nil { + return false, fmt.Errorf("trace for nested channel should not be empty") + } + if len(ncm.Trace.Events) == 0 { + return false, fmt.Errorf("there should be at least one trace event for nested channel not 0") + } + if ncm.Trace.Events[0].Desc != "Channel Created" { + return false, fmt.Errorf("the first trace event should be \"Channel Created\", not %q", ncm.Trace.Events[0].Desc) + } + return true, nil + }); err != nil { + t.Fatal(err) + } + + r.NewServiceConfig(`{"loadBalancingPolicy": "round_robin"}`) + r.NewAddress([]resolver.Address{{Addr: "127.0.0.1:0"}}) + + // wait for the shutdown of grpclb balancer + if err := verifyResultWithDelay(func() (bool, error) { + tcs, _ := channelz.GetTopChannels(0) + if len(tcs) != 1 { + return false, fmt.Errorf("there should only be one top channel, not %d", len(tcs)) + } + if len(tcs[0].NestedChans) != 0 { + return false, fmt.Errorf("there should be 0 nested channel from grpclb, not %d", len(tcs[0].NestedChans)) + } + ncm := channelz.GetChannel(nestedConn) + if ncm == nil { + return false, fmt.Errorf("nested channel should still exist due to parent's trace reference") + } + if ncm.Trace == nil { + return false, fmt.Errorf("trace for nested channel should not be empty") + } + if len(ncm.Trace.Events) == 0 { + return false, fmt.Errorf("there should be at least one trace event for nested channel not 0") + } + if ncm.Trace.Events[len(ncm.Trace.Events)-1].Desc != "Channel Deleted" { + return false, fmt.Errorf("the first trace event should be \"Channel Deleted\", not %q", ncm.Trace.Events[0].Desc) + } + return true, nil + }); err != nil { + t.Fatal(err) + } +} + +func TestCZSubChannelTraceCreationDeletion(t *testing.T) { + defer leakcheck.Check(t) + channelz.NewChannelzStorage() + e := tcpClearRREnv + te := newTest(t, e) + te.startServer(&testServer{security: e.security}) + r, cleanup := manual.GenerateAndRegisterManualResolver() + defer cleanup() + r.InitialAddrs([]resolver.Address{{Addr: te.srvAddr}}) + te.resolverScheme = r.Scheme() + te.clientConn() + defer te.tearDown() + var subConn int64 + // Here, we just wait for all sockets to be up. In the future, if we implement + // IDLE, we may need to make several rpc calls to create the sockets. + if err := verifyResultWithDelay(func() (bool, error) { + tcs, _ := channelz.GetTopChannels(0) + if len(tcs) != 1 { + return false, fmt.Errorf("there should only be one top channel, not %d", len(tcs)) + } + if len(tcs[0].SubChans) != 1 { + return false, fmt.Errorf("there should be 1 subchannel not %d", len(tcs[0].SubChans)) + } + for k := range tcs[0].SubChans { + subConn = k + } + for _, e := range tcs[0].Trace.Events { + if e.RefID == subConn && e.RefType != channelz.RefSubChannel { + return false, fmt.Errorf("subchannel trace event shoud have RefType to be RefSubChannel") + } + } + scm := channelz.GetSubChannel(subConn) + if scm == nil { + return false, fmt.Errorf("subChannel does not exist") + } + if scm.Trace == nil { + return false, fmt.Errorf("trace for subChannel should not be empty") + } + if len(scm.Trace.Events) == 0 { + return false, fmt.Errorf("there should be at least one trace event for subChannel not 0") + } + if scm.Trace.Events[0].Desc != "Subchannel Created" { + return false, fmt.Errorf("the first trace event should be \"Subchannel Created\", not %q", scm.Trace.Events[0].Desc) + } + return true, nil + }); err != nil { + t.Fatal(err) + } + + r.NewAddress([]resolver.Address{}) + + if err := verifyResultWithDelay(func() (bool, error) { + tcs, _ := channelz.GetTopChannels(0) + if len(tcs) != 1 { + return false, fmt.Errorf("there should only be one top channel, not %d", len(tcs)) + } + if len(tcs[0].SubChans) != 0 { + return false, fmt.Errorf("there should be 0 subchannel not %d", len(tcs[0].SubChans)) + } + scm := channelz.GetSubChannel(subConn) + if scm == nil { + return false, fmt.Errorf("subChannel should still exist due to parent's trace reference") + } + if scm.Trace == nil { + return false, fmt.Errorf("trace for SubChannel should not be empty") + } + if len(scm.Trace.Events) == 0 { + return false, fmt.Errorf("there should be at least one trace event for subChannel not 0") + } + if got, want := scm.Trace.Events[len(scm.Trace.Events)-1].Desc, "Subchannel Deleted"; got != want { + return false, fmt.Errorf("the last trace event should be %q, not %q", want, got) + } + + return true, nil + }); err != nil { + t.Fatal(err) + } +} + +func TestCZChannelAddressResolutionChange(t *testing.T) { + defer leakcheck.Check(t) + channelz.NewChannelzStorage() + e := tcpClearRREnv + e.balancer = "" + te := newTest(t, e) + te.startServer(&testServer{security: e.security}) + r, cleanup := manual.GenerateAndRegisterManualResolver() + defer cleanup() + r.InitialAddrs([]resolver.Address{{Addr: te.srvAddr}}) + te.resolverScheme = r.Scheme() + te.clientConn() + defer te.tearDown() + var cid int64 + // Here, we just wait for all sockets to be up. In the future, if we implement + // IDLE, we may need to make several rpc calls to create the sockets. + if err := verifyResultWithDelay(func() (bool, error) { + tcs, _ := channelz.GetTopChannels(0) + if len(tcs) != 1 { + return false, fmt.Errorf("there should only be one top channel, not %d", len(tcs)) + } + cid = tcs[0].ID + for i := len(tcs[0].Trace.Events) - 1; i >= 0; i-- { + if tcs[0].Trace.Events[i].Desc == fmt.Sprintf("Resolver returns a non-empty address list (previous one was empty) %q", te.srvAddr) { + break + } + if i == 0 { + return false, fmt.Errorf("events do not contain expected address resolution from empty address state") + } + } + return true, nil + }); err != nil { + t.Fatal(err) + } + + r.NewServiceConfig(`{"loadBalancingPolicy": "round_robin"}`) + + if err := verifyResultWithDelay(func() (bool, error) { + cm := channelz.GetChannel(cid) + for i := len(cm.Trace.Events) - 1; i >= 0; i-- { + if cm.Trace.Events[i].Desc == fmt.Sprintf("Channel switches to new LB policy %q", roundrobin.Name) { + break + } + if i == 0 { + return false, fmt.Errorf("events do not contain expected address resolution change of LB policy") + } + } + return true, nil + }); err != nil { + t.Fatal(err) + } + + newSc := `{ + "methodConfig": [ + { + "name": [ + { + "service": "grpc.testing.TestService", + "method": "EmptyCall" + }, + ], + "waitForReady": false, + "timeout": ".001s" + } + ] +}` + + r.NewServiceConfig(newSc) + + if err := verifyResultWithDelay(func() (bool, error) { + cm := channelz.GetChannel(cid) + + for i := len(cm.Trace.Events) - 1; i >= 0; i-- { + if cm.Trace.Events[i].Desc == fmt.Sprintf("Channel has a new service config \"%s\"", newSc) { + break + } + if i == 0 { + return false, fmt.Errorf("events do not contain expected address resolution of new service config") + } + } + return true, nil + }); err != nil { + t.Fatal(err) + } + + r.NewAddress([]resolver.Address{}) + + if err := verifyResultWithDelay(func() (bool, error) { + cm := channelz.GetChannel(cid) + for i := len(cm.Trace.Events) - 1; i >= 0; i-- { + if cm.Trace.Events[i].Desc == "Resolver returns an empty address list" { + break + } + if i == 0 { + return false, fmt.Errorf("events do not contain expected address resolution of empty address") + } + } + return true, nil + }); err != nil { + t.Fatal(err) + } +} + +func TestCZSubChannelPickedNewAddress(t *testing.T) { + defer leakcheck.Check(t) + channelz.NewChannelzStorage() + e := tcpClearRREnv + e.balancer = "" + te := newTest(t, e) + te.startServers(&testServer{security: e.security}, 3) + r, cleanup := manual.GenerateAndRegisterManualResolver() + defer cleanup() + var svrAddrs []resolver.Address + for _, a := range te.srvAddrs { + svrAddrs = append(svrAddrs, resolver.Address{Addr: a}) + } + r.InitialAddrs(svrAddrs) + te.resolverScheme = r.Scheme() + cc := te.clientConn() + defer te.tearDown() + tc := testpb.NewTestServiceClient(cc) + // make sure the connection is up + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); err != nil { + t.Fatalf("TestService/EmptyCall(_, _) = _, %v, want _, ", err) + } + te.srvs[0].Stop() + te.srvs[1].Stop() + // Here, we just wait for all sockets to be up. In the future, if we implement + // IDLE, we may need to make several rpc calls to create the sockets. + if err := verifyResultWithDelay(func() (bool, error) { + tcs, _ := channelz.GetTopChannels(0) + if len(tcs) != 1 { + return false, fmt.Errorf("there should only be one top channel, not %d", len(tcs)) + } + if len(tcs[0].SubChans) != 1 { + return false, fmt.Errorf("there should be 1 subchannel not %d", len(tcs[0].SubChans)) + } + var subConn int64 + for k := range tcs[0].SubChans { + subConn = k + } + scm := channelz.GetSubChannel(subConn) + if scm.Trace == nil { + return false, fmt.Errorf("trace for SubChannel should not be empty") + } + if len(scm.Trace.Events) == 0 { + return false, fmt.Errorf("there should be at least one trace event for subChannel not 0") + } + for i := len(scm.Trace.Events) - 1; i >= 0; i-- { + if scm.Trace.Events[i].Desc == fmt.Sprintf("Subchannel picks a new address %q to connect", te.srvAddrs[2]) { + break + } + if i == 0 { + return false, fmt.Errorf("events do not contain expected address resolution of subchannel picked new address") + } + } + return true, nil + }); err != nil { + t.Fatal(err) + } +} + +func TestCZSubChannelConnectivityState(t *testing.T) { + defer leakcheck.Check(t) + channelz.NewChannelzStorage() + e := tcpClearRREnv + te := newTest(t, e) + te.startServer(&testServer{security: e.security}) + r, cleanup := manual.GenerateAndRegisterManualResolver() + defer cleanup() + r.InitialAddrs([]resolver.Address{{Addr: te.srvAddr}}) + te.resolverScheme = r.Scheme() + te.customDialOptions = []grpc.DialOption{grpc.WithWaitForHandshake()} + cc := te.clientConn() + defer te.tearDown() + tc := testpb.NewTestServiceClient(cc) + // make sure the connection is up + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); err != nil { + t.Fatalf("TestService/EmptyCall(_, _) = _, %v, want _, ", err) + } + var subConn int64 + te.srv.Stop() + + if err := verifyResultWithDelay(func() (bool, error) { + // we need to obtain the SubChannel id before it gets deleted from Channel's children list (due + // to effect of r.NewAddress([]resolver.Address{})) + if subConn == 0 { + tcs, _ := channelz.GetTopChannels(0) + if len(tcs) != 1 { + return false, fmt.Errorf("there should only be one top channel, not %d", len(tcs)) + } + if len(tcs[0].SubChans) != 1 { + return false, fmt.Errorf("there should be 1 subchannel not %d", len(tcs[0].SubChans)) + } + for k := range tcs[0].SubChans { + // get the SubChannel id for further trace inquiry. + subConn = k + } + } + scm := channelz.GetSubChannel(subConn) + if scm == nil { + return false, fmt.Errorf("subChannel should still exist due to parent's trace reference") + } + if scm.Trace == nil { + return false, fmt.Errorf("trace for SubChannel should not be empty") + } + if len(scm.Trace.Events) == 0 { + return false, fmt.Errorf("there should be at least one trace event for subChannel not 0") + } + var ready, connecting, transient, shutdown int + for _, e := range scm.Trace.Events { + if e.Desc == fmt.Sprintf("Subchannel Connectivity change to %v", connectivity.TransientFailure) { + transient++ + } + } + // Make sure the SubChannel has already seen transient failure before shutting it down through + // r.NewAddress([]resolver.Address{}). + if transient == 0 { + return false, fmt.Errorf("transient failure has not happened on SubChannel yet") + } + transient = 0 + r.NewAddress([]resolver.Address{}) + for _, e := range scm.Trace.Events { + if e.Desc == fmt.Sprintf("Subchannel Connectivity change to %v", connectivity.Ready) { + ready++ + } + if e.Desc == fmt.Sprintf("Subchannel Connectivity change to %v", connectivity.Connecting) { + connecting++ + } + if e.Desc == fmt.Sprintf("Subchannel Connectivity change to %v", connectivity.TransientFailure) { + transient++ + } + if e.Desc == fmt.Sprintf("Subchannel Connectivity change to %v", connectivity.Shutdown) { + shutdown++ + } + } + // example: + // Subchannel Created + // Subchannel's connectivity state changed to CONNECTING + // Subchannel picked a new address: "localhost:36011" + // Subchannel's connectivity state changed to READY + // Subchannel's connectivity state changed to TRANSIENT_FAILURE + // Subchannel's connectivity state changed to CONNECTING + // Subchannel picked a new address: "localhost:36011" + // Subchannel's connectivity state changed to SHUTDOWN + // Subchannel Deleted + if ready != 1 || connecting < 1 || transient < 1 || shutdown != 1 { + return false, fmt.Errorf("got: ready = %d, connecting = %d, transient = %d, shutdown = %d, want: 1, >=1, >=1, 1", ready, connecting, transient, shutdown) + } + + return true, nil + }); err != nil { + t.Fatal(err) + } +} + +func TestCZChannelConnectivityState(t *testing.T) { + defer leakcheck.Check(t) + channelz.NewChannelzStorage() + e := tcpClearRREnv + te := newTest(t, e) + te.startServer(&testServer{security: e.security}) + r, cleanup := manual.GenerateAndRegisterManualResolver() + defer cleanup() + r.InitialAddrs([]resolver.Address{{Addr: te.srvAddr}}) + te.resolverScheme = r.Scheme() + te.customDialOptions = []grpc.DialOption{grpc.WithWaitForHandshake()} + cc := te.clientConn() + defer te.tearDown() + tc := testpb.NewTestServiceClient(cc) + // make sure the connection is up + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); err != nil { + t.Fatalf("TestService/EmptyCall(_, _) = _, %v, want _, ", err) + } + te.srv.Stop() + if err := verifyResultWithDelay(func() (bool, error) { + tcs, _ := channelz.GetTopChannels(0) + if len(tcs) != 1 { + return false, fmt.Errorf("there should only be one top channel, not %d", len(tcs)) + } + + var ready, connecting, transient int + for _, e := range tcs[0].Trace.Events { + if e.Desc == fmt.Sprintf("Channel Connectivity change to %v", connectivity.Ready) { + ready++ + } + if e.Desc == fmt.Sprintf("Channel Connectivity change to %v", connectivity.Connecting) { + connecting++ + } + if e.Desc == fmt.Sprintf("Channel Connectivity change to %v", connectivity.TransientFailure) { + transient++ + } + } + + // example: + // Channel Created + // Adressses resolved (from empty address state): "localhost:40467" + // SubChannel (id: 4[]) Created + // Channel's connectivity state changed to CONNECTING + // Channel's connectivity state changed to READY + // Channel's connectivity state changed to TRANSIENT_FAILURE + // Channel's connectivity state changed to CONNECTING + // Channel's connectivity state changed to TRANSIENT_FAILURE + if ready != 1 || connecting < 1 || transient < 1 { + return false, fmt.Errorf("got: ready = %d, connecting = %d, transient = %d, want: 1, >=1, >=1", ready, connecting, transient) + } + return true, nil + }); err != nil { + t.Fatal(err) + } +} + +func TestCZTraceOverwriteChannelDeletion(t *testing.T) { + defer leakcheck.Check(t) + channelz.NewChannelzStorage() + e := tcpClearRREnv + // avoid calling API to set balancer type, which will void service config's change of balancer. + e.balancer = "" + te := newTest(t, e) + channelz.SetMaxTraceEntry(1) + defer channelz.ResetMaxTraceEntryToDefault() + r, cleanup := manual.GenerateAndRegisterManualResolver() + defer cleanup() + resolvedAddrs := []resolver.Address{{Addr: "127.0.0.1:0", Type: resolver.GRPCLB, ServerName: "grpclb.server"}} + r.InitialAddrs(resolvedAddrs) + te.resolverScheme = r.Scheme() + te.clientConn() + defer te.tearDown() + var nestedConn int64 + if err := verifyResultWithDelay(func() (bool, error) { + tcs, _ := channelz.GetTopChannels(0) + if len(tcs) != 1 { + return false, fmt.Errorf("there should only be one top channel, not %d", len(tcs)) + } + if len(tcs[0].NestedChans) != 1 { + return false, fmt.Errorf("there should be one nested channel from grpclb, not %d", len(tcs[0].NestedChans)) + } + for k := range tcs[0].NestedChans { + nestedConn = k + } + return true, nil + }); err != nil { + t.Fatal(err) + } + + r.NewServiceConfig(`{"loadBalancingPolicy": "round_robin"}`) + r.NewAddress([]resolver.Address{{Addr: "127.0.0.1:0"}}) + + // wait for the shutdown of grpclb balancer + if err := verifyResultWithDelay(func() (bool, error) { + tcs, _ := channelz.GetTopChannels(0) + if len(tcs) != 1 { + return false, fmt.Errorf("there should only be one top channel, not %d", len(tcs)) + } + if len(tcs[0].NestedChans) != 0 { + return false, fmt.Errorf("there should be 0 nested channel from grpclb, not %d", len(tcs[0].NestedChans)) + } + return true, nil + }); err != nil { + t.Fatal(err) + } + + // verify that the nested channel no longer exist due to trace referencing it got overwritten. + if err := verifyResultWithDelay(func() (bool, error) { + cm := channelz.GetChannel(nestedConn) + if cm != nil { + return false, fmt.Errorf("nested channel should have been deleted since its parent's trace should not contain any reference to it anymore") + } + return true, nil + }); err != nil { + t.Fatal(err) + } +} + +func TestCZTraceOverwriteSubChannelDeletion(t *testing.T) { + defer leakcheck.Check(t) + channelz.NewChannelzStorage() + e := tcpClearRREnv + te := newTest(t, e) + channelz.SetMaxTraceEntry(1) + defer channelz.ResetMaxTraceEntryToDefault() + te.startServer(&testServer{security: e.security}) + r, cleanup := manual.GenerateAndRegisterManualResolver() + defer cleanup() + r.InitialAddrs([]resolver.Address{{Addr: te.srvAddr}}) + te.resolverScheme = r.Scheme() + te.clientConn() + defer te.tearDown() + var subConn int64 + // Here, we just wait for all sockets to be up. In the future, if we implement + // IDLE, we may need to make several rpc calls to create the sockets. + if err := verifyResultWithDelay(func() (bool, error) { + tcs, _ := channelz.GetTopChannels(0) + if len(tcs) != 1 { + return false, fmt.Errorf("there should only be one top channel, not %d", len(tcs)) + } + if len(tcs[0].SubChans) != 1 { + return false, fmt.Errorf("there should be 1 subchannel not %d", len(tcs[0].SubChans)) + } + for k := range tcs[0].SubChans { + subConn = k + } + return true, nil + }); err != nil { + t.Fatal(err) + } + + r.NewAddress([]resolver.Address{}) + + if err := verifyResultWithDelay(func() (bool, error) { + tcs, _ := channelz.GetTopChannels(0) + if len(tcs) != 1 { + return false, fmt.Errorf("there should only be one top channel, not %d", len(tcs)) + } + if len(tcs[0].SubChans) != 0 { + return false, fmt.Errorf("there should be 0 subchannel not %d", len(tcs[0].SubChans)) + } + return true, nil + }); err != nil { + t.Fatal(err) + } + + // verify that the subchannel no longer exist due to trace referencing it got overwritten. + if err := verifyResultWithDelay(func() (bool, error) { + cm := channelz.GetChannel(subConn) + if cm != nil { + return false, fmt.Errorf("subchannel should have been deleted since its parent's trace should not contain any reference to it anymore") + } + return true, nil + }); err != nil { + t.Fatal(err) + } +} + +func TestCZTraceTopChannelDeletionTraceClear(t *testing.T) { + defer leakcheck.Check(t) + channelz.NewChannelzStorage() + e := tcpClearRREnv + te := newTest(t, e) + te.startServer(&testServer{security: e.security}) + r, cleanup := manual.GenerateAndRegisterManualResolver() + defer cleanup() + r.InitialAddrs([]resolver.Address{{Addr: te.srvAddr}}) + te.resolverScheme = r.Scheme() + te.clientConn() + var subConn int64 + // Here, we just wait for all sockets to be up. In the future, if we implement + // IDLE, we may need to make several rpc calls to create the sockets. + if err := verifyResultWithDelay(func() (bool, error) { + tcs, _ := channelz.GetTopChannels(0) + if len(tcs) != 1 { + return false, fmt.Errorf("there should only be one top channel, not %d", len(tcs)) + } + if len(tcs[0].SubChans) != 1 { + return false, fmt.Errorf("there should be 1 subchannel not %d", len(tcs[0].SubChans)) + } + for k := range tcs[0].SubChans { + subConn = k + } + return true, nil + }); err != nil { + t.Fatal(err) + } + te.tearDown() + // verify that the subchannel no longer exist due to parent channel got deleted and its trace cleared. + if err := verifyResultWithDelay(func() (bool, error) { + cm := channelz.GetChannel(subConn) + if cm != nil { + return false, fmt.Errorf("subchannel should have been deleted since its parent's trace should not contain any reference to it anymore") } return true, nil }); err != nil { diff --git a/vendor/google.golang.org/grpc/test/creds_test.go b/vendor/google.golang.org/grpc/test/creds_test.go new file mode 100644 index 0000000000000000000000000000000000000000..58418f782112abcb4443040016d81c8006ccf72f --- /dev/null +++ b/vendor/google.golang.org/grpc/test/creds_test.go @@ -0,0 +1,131 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package test + +// TODO(https://github.com/grpc/grpc-go/issues/2330): move all creds releated +// tests to this file. + +import ( + "context" + "testing" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/internal/leakcheck" + testpb "google.golang.org/grpc/test/grpc_testing" + "google.golang.org/grpc/testdata" +) + +const ( + bundlePerRPCOnly = "perRPCOnly" + bundleTLSOnly = "tlsOnly" +) + +type testCredsBundle struct { + t *testing.T + mode string +} + +func (c *testCredsBundle) TransportCredentials() credentials.TransportCredentials { + if c.mode == bundlePerRPCOnly { + return nil + } + + creds, err := credentials.NewClientTLSFromFile(testdata.Path("ca.pem"), "x.test.youtube.com") + if err != nil { + c.t.Logf("Failed to load credentials: %v", err) + return nil + } + return creds +} + +func (c *testCredsBundle) PerRPCCredentials() credentials.PerRPCCredentials { + if c.mode == bundleTLSOnly { + return nil + } + return testPerRPCCredentials{} +} + +func (c *testCredsBundle) NewWithMode(mode string) (credentials.Bundle, error) { + return &testCredsBundle{mode: mode}, nil +} + +func TestCredsBundleBoth(t *testing.T) { + defer leakcheck.Check(t) + te := newTest(t, env{name: "creds-bundle", network: "tcp", balancer: "v1", security: "empty"}) + te.tapHandle = authHandle + te.customDialOptions = []grpc.DialOption{ + grpc.WithCredentialsBundle(&testCredsBundle{t: t}), + } + creds, err := credentials.NewServerTLSFromFile(testdata.Path("server1.pem"), testdata.Path("server1.key")) + if err != nil { + t.Fatalf("Failed to generate credentials %v", err) + } + te.customServerOptions = []grpc.ServerOption{ + grpc.Creds(creds), + } + te.startServer(&testServer{}) + defer te.tearDown() + + cc := te.clientConn() + tc := testpb.NewTestServiceClient(cc) + if _, err := tc.EmptyCall(context.Background(), &testpb.Empty{}); err != nil { + t.Fatalf("Test failed. Reason: %v", err) + } +} + +func TestCredsBundleTransportCredentials(t *testing.T) { + defer leakcheck.Check(t) + te := newTest(t, env{name: "creds-bundle", network: "tcp", balancer: "v1", security: "empty"}) + te.customDialOptions = []grpc.DialOption{ + grpc.WithCredentialsBundle(&testCredsBundle{t: t, mode: bundleTLSOnly}), + } + creds, err := credentials.NewServerTLSFromFile(testdata.Path("server1.pem"), testdata.Path("server1.key")) + if err != nil { + t.Fatalf("Failed to generate credentials %v", err) + } + te.customServerOptions = []grpc.ServerOption{ + grpc.Creds(creds), + } + te.startServer(&testServer{}) + defer te.tearDown() + + cc := te.clientConn() + tc := testpb.NewTestServiceClient(cc) + if _, err := tc.EmptyCall(context.Background(), &testpb.Empty{}); err != nil { + t.Fatalf("Test failed. Reason: %v", err) + } +} + +func TestCredsBundlePerRPCCredentials(t *testing.T) { + defer leakcheck.Check(t) + te := newTest(t, env{name: "creds-bundle", network: "tcp", balancer: "v1", security: "empty"}) + te.tapHandle = authHandle + te.customDialOptions = []grpc.DialOption{ + grpc.WithCredentialsBundle(&testCredsBundle{t: t, mode: bundlePerRPCOnly}), + } + te.startServer(&testServer{}) + defer te.tearDown() + + cc := te.clientConn() + tc := testpb.NewTestServiceClient(cc) + if _, err := tc.EmptyCall(context.Background(), &testpb.Empty{}); err != nil { + t.Fatalf("Test failed. Reason: %v", err) + } +} diff --git a/vendor/google.golang.org/grpc/test/end2end_test.go b/vendor/google.golang.org/grpc/test/end2end_test.go index 6574a64fc5c1407fe0c7404367edcbc47427aa1f..8fdca906a29e6efd1b5930d185c54a9d6b3dddc5 100644 --- a/vendor/google.golang.org/grpc/test/end2end_test.go +++ b/vendor/google.golang.org/grpc/test/end2end_test.go @@ -23,6 +23,7 @@ package test import ( "bytes" + "context" "crypto/tls" "errors" "flag" @@ -30,6 +31,7 @@ import ( "io" "math" "net" + "net/http" "os" "reflect" "runtime" @@ -42,7 +44,6 @@ import ( "github.com/golang/protobuf/proto" anypb "github.com/golang/protobuf/ptypes/any" - "golang.org/x/net/context" "golang.org/x/net/http2" spb "google.golang.org/genproto/googleapis/rpc/status" "google.golang.org/grpc" @@ -55,8 +56,10 @@ import ( "google.golang.org/grpc/health" healthgrpc "google.golang.org/grpc/health/grpc_health_v1" healthpb "google.golang.org/grpc/health/grpc_health_v1" - "google.golang.org/grpc/internal" + "google.golang.org/grpc/internal/channelz" + "google.golang.org/grpc/internal/grpcsync" "google.golang.org/grpc/internal/leakcheck" + "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" @@ -71,7 +74,7 @@ import ( ) func init() { - grpc.RegisterChannelz() + channelz.TurnOn() } var ( @@ -452,6 +455,8 @@ type test struct { maxClientSendMsgSize *int maxServerReceiveMsgSize *int maxServerSendMsgSize *int + maxClientHeaderListSize *uint32 + maxServerHeaderListSize *uint32 userAgent string // clientCompression and serverCompression are set to test the deprecated API // WithCompressor and WithDecompressor. @@ -474,6 +479,7 @@ type test struct { clientInitialConnWindowSize int32 perRPCCreds credentials.PerRPCCredentials customDialOptions []grpc.DialOption + customServerOptions []grpc.ServerOption resolverScheme string cliKeepAlive *keepalive.ClientParameters svrKeepAlive *keepalive.ServerParameters @@ -483,7 +489,7 @@ type test struct { nonBlockingDial bool // srv and srvAddr are set once startServer is called. - srv *grpc.Server + srv stopper srvAddr string // srvs and srvAddrs are set once startServers is called. @@ -494,6 +500,11 @@ type test struct { restoreLogs func() // nil unless declareLogNoise is used } +type stopper interface { + Stop() + GracefulStop() +} + func (te *test) tearDown() { if te.cancel != nil { te.cancel() @@ -546,6 +557,9 @@ func (te *test) listenAndServe(ts testpb.TestServiceServer, listen func(network, if te.maxServerSendMsgSize != nil { sopts = append(sopts, grpc.MaxSendMsgSize(*te.maxServerSendMsgSize)) } + if te.maxServerHeaderListSize != nil { + sopts = append(sopts, grpc.MaxHeaderListSize(*te.maxServerHeaderListSize)) + } if te.tapHandle != nil { sopts = append(sopts, grpc.InTapHandle(te.tapHandle)) } @@ -596,11 +610,9 @@ func (te *test) listenAndServe(ts testpb.TestServiceServer, listen func(network, if te.svrKeepAlive != nil { sopts = append(sopts, grpc.KeepaliveParams(*te.svrKeepAlive)) } + sopts = append(sopts, te.customServerOptions...) s := grpc.NewServer(sopts...) te.srv = s - if te.e.httpHandler { - internal.TestingUseHandlerImpl(s) - } if te.healthServer != nil { healthgrpc.RegisterHealthServer(s, te.healthServer) } @@ -618,11 +630,100 @@ func (te *test) listenAndServe(ts testpb.TestServiceServer, listen func(network, addr = "localhost:" + port } - go s.Serve(lis) te.srvAddr = addr + + if te.e.httpHandler { + if te.e.security != "tls" { + te.t.Fatalf("unsupported environment settings") + } + cert, err := tls.LoadX509KeyPair(testdata.Path("server1.pem"), testdata.Path("server1.key")) + if err != nil { + te.t.Fatal("Error creating TLS certificate: ", err) + } + hs := &http.Server{ + Handler: s, + } + err = http2.ConfigureServer(hs, &http2.Server{ + MaxConcurrentStreams: te.maxStream, + }) + if err != nil { + te.t.Fatal("error starting http2 server: ", err) + } + hs.TLSConfig.Certificates = []tls.Certificate{cert} + tlsListener := tls.NewListener(lis, hs.TLSConfig) + whs := &wrapHS{Listener: tlsListener, s: hs, conns: make(map[net.Conn]bool)} + te.srv = whs + go hs.Serve(whs) + + return lis + } + + go s.Serve(lis) return lis } +// TODO: delete wrapHS and wrapConn when Go1.6 and Go1.7 support are gone and +// call s.Close and s.Shutdown instead. +type wrapHS struct { + sync.Mutex + net.Listener + s *http.Server + conns map[net.Conn]bool +} + +func (w *wrapHS) Accept() (net.Conn, error) { + c, err := w.Listener.Accept() + if err != nil { + return nil, err + } + w.Lock() + if w.conns == nil { + w.Unlock() + c.Close() + return nil, errors.New("connection after listener closed") + } + w.conns[&wrapConn{Conn: c, hs: w}] = true + w.Unlock() + return c, nil +} + +func (w *wrapHS) Stop() { + w.Listener.Close() + w.Lock() + conns := w.conns + w.conns = nil + w.Unlock() + for c := range conns { + c.Close() + } +} + +// Poll for now.. +func (w *wrapHS) GracefulStop() { + w.Listener.Close() + for { + w.Lock() + l := len(w.conns) + w.Unlock() + if l == 0 { + return + } + time.Sleep(50 * time.Millisecond) + } +} + +type wrapConn struct { + net.Conn + hs *wrapHS +} + +func (w *wrapConn) Close() error { + w.hs.Lock() + delete(w.hs.conns, w.Conn) + w.hs.Unlock() + return w.Conn.Close() +} + func (te *test) startServerWithConnControl(ts testpb.TestServiceServer) *listenerWrapper { l := te.listenAndServe(ts, listenWithConnControl) return l.(*listenerWrapper) @@ -697,6 +798,9 @@ func (te *test) configDial(opts ...grpc.DialOption) ([]grpc.DialOption, string) if te.maxClientSendMsgSize != nil { opts = append(opts, grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(*te.maxClientSendMsgSize))) } + if te.maxClientHeaderListSize != nil { + opts = append(opts, grpc.WithMaxHeaderListSize(*te.maxClientHeaderListSize)) + } switch te.e.security { case "tls": creds, err := credentials.NewClientTLSFromFile(testdata.Path("ca.pem"), "x.test.youtube.com") @@ -706,6 +810,8 @@ func (te *test) configDial(opts ...grpc.DialOption) ([]grpc.DialOption, string) opts = append(opts, grpc.WithTransportCredentials(creds)) case "clientTimeoutCreds": opts = append(opts, grpc.WithTransportCredentials(&clientTimeoutCreds{})) + case "empty": + // Don't add any transport creds option. default: opts = append(opts, grpc.WithInsecure()) } @@ -1888,9 +1994,7 @@ func TestStreamingRPCWithTimeoutInServiceConfigRecv(t *testing.T) { te.resolverScheme = r.Scheme() te.nonBlockingDial = true - fmt.Println("1") cc := te.clientConn() - fmt.Println("10") tc := testpb.NewTestServiceClient(cc) r.NewAddress([]resolver.Address{{Addr: te.srvAddr}}) @@ -2330,6 +2434,260 @@ func testHealthCheckOff(t *testing.T, e env) { } } +func TestHealthWatchMultipleClients(t *testing.T) { + defer leakcheck.Check(t) + for _, e := range listTestEnv() { + testHealthWatchMultipleClients(t, e) + } +} + +func testHealthWatchMultipleClients(t *testing.T, e env) { + const service = "grpc.health.v1.Health1" + + hs := health.NewServer() + + te := newTest(t, e) + te.healthServer = hs + te.startServer(&testServer{security: e.security}) + defer te.tearDown() + + cc := te.clientConn() + hc := healthgrpc.NewHealthClient(cc) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + req := &healthpb.HealthCheckRequest{ + Service: service, + } + + stream1, err := hc.Watch(ctx, req) + if err != nil { + t.Fatalf("error: %v", err) + } + + healthWatchChecker(t, stream1, healthpb.HealthCheckResponse_SERVICE_UNKNOWN) + + stream2, err := hc.Watch(ctx, req) + if err != nil { + t.Fatalf("error: %v", err) + } + + healthWatchChecker(t, stream2, healthpb.HealthCheckResponse_SERVICE_UNKNOWN) + + hs.SetServingStatus(service, healthpb.HealthCheckResponse_NOT_SERVING) + + healthWatchChecker(t, stream1, healthpb.HealthCheckResponse_NOT_SERVING) + healthWatchChecker(t, stream2, healthpb.HealthCheckResponse_NOT_SERVING) +} + +func TestHealthWatchSameStatus(t *testing.T) { + defer leakcheck.Check(t) + for _, e := range listTestEnv() { + testHealthWatchSameStatus(t, e) + } +} + +func testHealthWatchSameStatus(t *testing.T, e env) { + const service = "grpc.health.v1.Health1" + + hs := health.NewServer() + + te := newTest(t, e) + te.healthServer = hs + te.startServer(&testServer{security: e.security}) + defer te.tearDown() + + cc := te.clientConn() + hc := healthgrpc.NewHealthClient(cc) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + req := &healthpb.HealthCheckRequest{ + Service: service, + } + + stream1, err := hc.Watch(ctx, req) + if err != nil { + t.Fatalf("error: %v", err) + } + + healthWatchChecker(t, stream1, healthpb.HealthCheckResponse_SERVICE_UNKNOWN) + + hs.SetServingStatus(service, healthpb.HealthCheckResponse_SERVING) + + healthWatchChecker(t, stream1, healthpb.HealthCheckResponse_SERVING) + + hs.SetServingStatus(service, healthpb.HealthCheckResponse_SERVING) + hs.SetServingStatus(service, healthpb.HealthCheckResponse_NOT_SERVING) + + healthWatchChecker(t, stream1, healthpb.HealthCheckResponse_NOT_SERVING) +} + +func TestHealthWatchServiceStatusSetBeforeStartingServer(t *testing.T) { + defer leakcheck.Check(t) + for _, e := range listTestEnv() { + testHealthWatchSetServiceStatusBeforeStartingServer(t, e) + } +} + +func testHealthWatchSetServiceStatusBeforeStartingServer(t *testing.T, e env) { + const service = "grpc.health.v1.Health1" + + hs := health.NewServer() + + te := newTest(t, e) + te.healthServer = hs + + hs.SetServingStatus(service, healthpb.HealthCheckResponse_SERVING) + + te.startServer(&testServer{security: e.security}) + defer te.tearDown() + + cc := te.clientConn() + hc := healthgrpc.NewHealthClient(cc) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + req := &healthpb.HealthCheckRequest{ + Service: service, + } + + stream, err := hc.Watch(ctx, req) + if err != nil { + t.Fatalf("error: %v", err) + } + + healthWatchChecker(t, stream, healthpb.HealthCheckResponse_SERVING) +} + +func TestHealthWatchDefaultStatusChange(t *testing.T) { + defer leakcheck.Check(t) + for _, e := range listTestEnv() { + testHealthWatchDefaultStatusChange(t, e) + } +} + +func testHealthWatchDefaultStatusChange(t *testing.T, e env) { + const service = "grpc.health.v1.Health1" + + hs := health.NewServer() + + te := newTest(t, e) + te.healthServer = hs + te.startServer(&testServer{security: e.security}) + defer te.tearDown() + + cc := te.clientConn() + hc := healthgrpc.NewHealthClient(cc) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + req := &healthpb.HealthCheckRequest{ + Service: service, + } + + stream, err := hc.Watch(ctx, req) + if err != nil { + t.Fatalf("error: %v", err) + } + + healthWatchChecker(t, stream, healthpb.HealthCheckResponse_SERVICE_UNKNOWN) + + hs.SetServingStatus(service, healthpb.HealthCheckResponse_SERVING) + + healthWatchChecker(t, stream, healthpb.HealthCheckResponse_SERVING) +} + +func TestHealthWatchSetServiceStatusBeforeClientCallsWatch(t *testing.T) { + defer leakcheck.Check(t) + for _, e := range listTestEnv() { + testHealthWatchSetServiceStatusBeforeClientCallsWatch(t, e) + } +} + +func testHealthWatchSetServiceStatusBeforeClientCallsWatch(t *testing.T, e env) { + const service = "grpc.health.v1.Health1" + + hs := health.NewServer() + + te := newTest(t, e) + te.healthServer = hs + te.startServer(&testServer{security: e.security}) + defer te.tearDown() + + cc := te.clientConn() + hc := healthgrpc.NewHealthClient(cc) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + req := &healthpb.HealthCheckRequest{ + Service: service, + } + + hs.SetServingStatus(service, healthpb.HealthCheckResponse_SERVING) + + stream, err := hc.Watch(ctx, req) + if err != nil { + t.Fatalf("error: %v", err) + } + + healthWatchChecker(t, stream, healthpb.HealthCheckResponse_SERVING) +} + +func TestHealthWatchOverallServerHealthChange(t *testing.T) { + defer leakcheck.Check(t) + for _, e := range listTestEnv() { + testHealthWatchOverallServerHealthChange(t, e) + } +} + +func testHealthWatchOverallServerHealthChange(t *testing.T, e env) { + const service = "" + + hs := health.NewServer() + + te := newTest(t, e) + te.healthServer = hs + te.startServer(&testServer{security: e.security}) + defer te.tearDown() + + cc := te.clientConn() + hc := healthgrpc.NewHealthClient(cc) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + req := &healthpb.HealthCheckRequest{ + Service: service, + } + + stream, err := hc.Watch(ctx, req) + if err != nil { + t.Fatalf("error: %v", err) + } + + healthWatchChecker(t, stream, healthpb.HealthCheckResponse_SERVING) + + hs.SetServingStatus(service, healthpb.HealthCheckResponse_NOT_SERVING) + + healthWatchChecker(t, stream, healthpb.HealthCheckResponse_NOT_SERVING) +} + +func healthWatchChecker(t *testing.T, stream healthgrpc.Health_WatchClient, expectedServingStatus healthpb.HealthCheckResponse_ServingStatus) { + response, err := stream.Recv() + if err != nil { + t.Fatalf("error on %v.Recv(): %v", stream, err) + } + if response.Status != expectedServingStatus { + t.Fatalf("response.Status is %v (%v expected)", response.Status, expectedServingStatus) + } +} + func TestUnknownHandler(t *testing.T) { defer leakcheck.Check(t) // An example unknownHandler that returns a different code and a different method, making sure that we do not @@ -2961,10 +3319,6 @@ func testSetAndSendHeaderStreamingRPC(t *testing.T, e env) { defer te.tearDown() tc := testpb.NewTestServiceClient(te.clientConn()) - const ( - argSize = 1 - respSize = 1 - ) ctx := metadata.NewOutgoingContext(context.Background(), testMetadata) stream, err := tc.FullDuplexCall(ctx) if err != nil { @@ -3075,7 +3429,9 @@ func testMultipleSetHeaderStreamingRPCError(t *testing.T, e env) { argSize = 1 respSize = -1 ) - ctx := metadata.NewOutgoingContext(context.Background(), testMetadata) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + ctx = metadata.NewOutgoingContext(ctx, testMetadata) stream, err := tc.FullDuplexCall(ctx) if err != nil { t.Fatalf("%v.FullDuplexCall(_) = _, %v, want ", tc, err) @@ -3151,20 +3507,20 @@ func testMalformedHTTP2Metadata(t *testing.T, e env) { } } -func TestRetry(t *testing.T) { +func TestTransparentRetry(t *testing.T) { defer leakcheck.Check(t) for _, e := range listTestEnv() { if e.name == "handler-tls" { // Fails with RST_STREAM / FLOW_CONTROL_ERROR continue } - testRetry(t, e) + testTransparentRetry(t, e) } } -// This test make sure RPCs are retried times when they receive a RST_STREAM +// This test makes sure RPCs are retried times when they receive a RST_STREAM // with the REFUSED_STREAM error code, which the InTapHandle provokes. -func testRetry(t *testing.T, e env) { +func testTransparentRetry(t *testing.T, e env) { te := newTest(t, e) attempts := 0 successAttempt := 2 @@ -4559,9 +4915,7 @@ func TestCredsHandshakeAuthority(t *testing.T) { } } -type clientFailCreds struct { - got string -} +type clientFailCreds struct{} func (c *clientFailCreds) ServerHandshake(rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) { return rawConn, nil, nil @@ -4845,8 +5199,11 @@ type stubServer struct { // A client connected to this service the test may use. Created in Start(). client testpb.TestServiceClient + cc *grpc.ClientConn cleanups []func() // Lambdas executed in Stop(); populated by Start(). + + r *manual.Resolver } func (ss *stubServer) EmptyCall(ctx context.Context, in *testpb.Empty) (*testpb.Empty, error) { @@ -4858,7 +5215,11 @@ func (ss *stubServer) FullDuplexCall(stream testpb.TestService_FullDuplexCallSer } // Start starts the server and creates a client connected to it. -func (ss *stubServer) Start(sopts []grpc.ServerOption) error { +func (ss *stubServer) Start(sopts []grpc.ServerOption, dopts ...grpc.DialOption) error { + r, cleanup := manual.GenerateAndRegisterManualResolver() + ss.r = r + ss.cleanups = append(ss.cleanups, cleanup) + lis, err := net.Listen("tcp", "localhost:0") if err != nil { return fmt.Errorf(`net.Listen("tcp", "localhost:0") = %v`, err) @@ -4870,16 +5231,40 @@ func (ss *stubServer) Start(sopts []grpc.ServerOption) error { go s.Serve(lis) ss.cleanups = append(ss.cleanups, s.Stop) - cc, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure(), grpc.WithBlock()) + target := ss.r.Scheme() + ":///" + lis.Addr().String() + + opts := append([]grpc.DialOption{grpc.WithInsecure()}, dopts...) + cc, err := grpc.Dial(target, opts...) if err != nil { - return fmt.Errorf("grpc.Dial(%q) = %v", lis.Addr().String(), err) + return fmt.Errorf("grpc.Dial(%q) = %v", target, err) } + ss.cc = cc + ss.r.NewAddress([]resolver.Address{{Addr: lis.Addr().String()}}) + if err := ss.waitForReady(cc); err != nil { + return err + } + ss.cleanups = append(ss.cleanups, func() { cc.Close() }) ss.client = testpb.NewTestServiceClient(cc) return nil } +func (ss *stubServer) waitForReady(cc *grpc.ClientConn) error { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + for { + s := cc.GetState() + if s == connectivity.Ready { + return nil + } + if !cc.WaitForStateChange(ctx, s) { + // ctx got timeout or canceled. + return ctx.Err() + } + } +} + func (ss *stubServer) Stop() { for i := len(ss.cleanups) - 1; i >= 0; i-- { ss.cleanups[i]() @@ -5125,7 +5510,7 @@ func TestClientWriteFailsAfterServerClosesStream(t *testing.T) { } sopts := []grpc.ServerOption{} if err := ss.Start(sopts); err != nil { - t.Fatalf("Error starting endpoing server: %v", err) + t.Fatalf("Error starting endpoint server: %v", err) } defer ss.Stop() ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -5143,7 +5528,6 @@ func TestClientWriteFailsAfterServerClosesStream(t *testing.T) { t.Fatalf("stream.Send(_) = %v, want io.EOF", err) } } - } type windowSizeConfig struct { @@ -6340,3 +6724,478 @@ func testRPCTimeout(t *testing.T, e env) { cancel() } } + +func TestDisabledIOBuffers(t *testing.T) { + defer leakcheck.Check(t) + + payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(60000)) + if err != nil { + t.Fatalf("Failed to create payload: %v", err) + } + req := &testpb.StreamingOutputCallRequest{ + Payload: payload, + } + resp := &testpb.StreamingOutputCallResponse{ + Payload: payload, + } + + ss := &stubServer{ + fullDuplexCall: func(stream testpb.TestService_FullDuplexCallServer) error { + for { + in, err := stream.Recv() + if err == io.EOF { + return nil + } + if err != nil { + t.Errorf("stream.Recv() = _, %v, want _, ", err) + return err + } + if !reflect.DeepEqual(in.Payload.Body, payload.Body) { + t.Errorf("Received message(len: %v) on server not what was expected(len: %v).", len(in.Payload.Body), len(payload.Body)) + return err + } + if err := stream.Send(resp); err != nil { + t.Errorf("stream.Send(_)= %v, want ", err) + return err + } + + } + }, + } + + s := grpc.NewServer(grpc.WriteBufferSize(0), grpc.ReadBufferSize(0)) + testpb.RegisterTestServiceServer(s, ss) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("Failed to create listener: %v", err) + } + + done := make(chan struct{}) + go func() { + s.Serve(lis) + close(done) + }() + defer s.Stop() + dctx, dcancel := context.WithTimeout(context.Background(), 5*time.Second) + defer dcancel() + cc, err := grpc.DialContext(dctx, lis.Addr().String(), grpc.WithInsecure(), grpc.WithBlock(), grpc.WithWriteBufferSize(0), grpc.WithReadBufferSize(0)) + if err != nil { + t.Fatalf("Failed to dial server") + } + defer cc.Close() + c := testpb.NewTestServiceClient(cc) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + stream, err := c.FullDuplexCall(ctx, grpc.FailFast(false)) + if err != nil { + t.Fatalf("Failed to send test RPC to server") + } + for i := 0; i < 10; i++ { + if err := stream.Send(req); err != nil { + t.Fatalf("stream.Send(_) = %v, want ", err) + } + in, err := stream.Recv() + if err != nil { + t.Fatalf("stream.Recv() = _, %v, want _, ", err) + } + if !reflect.DeepEqual(in.Payload.Body, payload.Body) { + t.Fatalf("Received message(len: %v) on client not what was expected(len: %v).", len(in.Payload.Body), len(payload.Body)) + } + } + stream.CloseSend() + if _, err := stream.Recv(); err != io.EOF { + t.Fatalf("stream.Recv() = _, %v, want _, io.EOF", err) + } +} + +func TestServerMaxHeaderListSizeClientUserViolation(t *testing.T) { + defer leakcheck.Check(t) + for _, e := range listTestEnv() { + if e.httpHandler { + continue + } + testServerMaxHeaderListSizeClientUserViolation(t, e) + } +} + +func testServerMaxHeaderListSizeClientUserViolation(t *testing.T, e env) { + te := newTest(t, e) + te.maxServerHeaderListSize = new(uint32) + *te.maxServerHeaderListSize = 216 + te.startServer(&testServer{security: e.security}) + defer te.tearDown() + + cc := te.clientConn() + tc := testpb.NewTestServiceClient(cc) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + metadata.AppendToOutgoingContext(ctx, "oversize", string(make([]byte, 216))) + var err error + if err = verifyResultWithDelay(func() (bool, error) { + if _, err = tc.EmptyCall(ctx, &testpb.Empty{}); err != nil && status.Code(err) == codes.Internal { + return true, nil + } + return false, fmt.Errorf("tc.EmptyCall() = _, err: %v, want _, error code: %v", err, codes.Internal) + }); err != nil { + t.Fatal(err) + } +} + +func TestClientMaxHeaderListSizeServerUserViolation(t *testing.T) { + defer leakcheck.Check(t) + for _, e := range listTestEnv() { + if e.httpHandler { + continue + } + testClientMaxHeaderListSizeServerUserViolation(t, e) + } +} + +func testClientMaxHeaderListSizeServerUserViolation(t *testing.T, e env) { + te := newTest(t, e) + te.maxClientHeaderListSize = new(uint32) + *te.maxClientHeaderListSize = 1 // any header server sends will violate + te.startServer(&testServer{security: e.security}) + defer te.tearDown() + + cc := te.clientConn() + tc := testpb.NewTestServiceClient(cc) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + var err error + if err = verifyResultWithDelay(func() (bool, error) { + if _, err = tc.EmptyCall(ctx, &testpb.Empty{}); err != nil && status.Code(err) == codes.Internal { + return true, nil + } + return false, fmt.Errorf("tc.EmptyCall() = _, err: %v, want _, error code: %v", err, codes.Internal) + }); err != nil { + t.Fatal(err) + } +} + +func TestServerMaxHeaderListSizeClientIntentionalViolation(t *testing.T) { + defer leakcheck.Check(t) + for _, e := range listTestEnv() { + if e.httpHandler || e.security == "tls" { + continue + } + testServerMaxHeaderListSizeClientIntentionalViolation(t, e) + } +} + +func testServerMaxHeaderListSizeClientIntentionalViolation(t *testing.T, e env) { + te := newTest(t, e) + te.maxServerHeaderListSize = new(uint32) + *te.maxServerHeaderListSize = 512 + te.startServer(&testServer{security: e.security}) + defer te.tearDown() + + cc, dw := te.clientConnWithConnControl() + tc := &testServiceClientWrapper{TestServiceClient: testpb.NewTestServiceClient(cc)} + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + stream, err := tc.FullDuplexCall(ctx) + if err != nil { + t.Fatalf("%v.FullDuplexCall(_) = _, %v, want _, ", tc, err) + } + rcw := dw.getRawConnWrapper() + val := make([]string, 512) + for i := range val { + val[i] = "a" + } + // allow for client to send the initial header + time.Sleep(100 * time.Millisecond) + rcw.writeHeaders(http2.HeadersFrameParam{ + StreamID: tc.getCurrentStreamID(), + BlockFragment: rcw.encodeHeader("oversize", strings.Join(val, "")), + EndStream: false, + EndHeaders: true, + }) + if _, err := stream.Recv(); err == nil || status.Code(err) != codes.Internal { + t.Fatalf("stream.Recv() = _, %v, want _, error code: %v", err, codes.Internal) + } +} + +func TestClientMaxHeaderListSizeServerIntentionalViolation(t *testing.T) { + defer leakcheck.Check(t) + for _, e := range listTestEnv() { + if e.httpHandler || e.security == "tls" { + continue + } + testClientMaxHeaderListSizeServerIntentionalViolation(t, e) + } +} + +func testClientMaxHeaderListSizeServerIntentionalViolation(t *testing.T, e env) { + te := newTest(t, e) + te.maxClientHeaderListSize = new(uint32) + *te.maxClientHeaderListSize = 200 + lw := te.startServerWithConnControl(&testServer{security: e.security, setHeaderOnly: true}) + defer te.tearDown() + cc, _ := te.clientConnWithConnControl() + tc := &testServiceClientWrapper{TestServiceClient: testpb.NewTestServiceClient(cc)} + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + stream, err := tc.FullDuplexCall(ctx) + if err != nil { + t.Fatalf("%v.FullDuplexCall(_) = _, %v, want _, ", tc, err) + } + var i int + var rcw *rawConnWrapper + for i = 0; i < 100; i++ { + rcw = lw.getLastConn() + if rcw != nil { + break + } + time.Sleep(10 * time.Millisecond) + continue + } + if i == 100 { + t.Fatalf("failed to create server transport after 1s") + } + + val := make([]string, 200) + for i := range val { + val[i] = "a" + } + // allow for client to send the initial header. + time.Sleep(100 * time.Millisecond) + rcw.writeHeaders(http2.HeadersFrameParam{ + StreamID: tc.getCurrentStreamID(), + BlockFragment: rcw.encodeHeader("oversize", strings.Join(val, "")), + EndStream: false, + EndHeaders: true, + }) + if _, err := stream.Recv(); err == nil || status.Code(err) != codes.Internal { + t.Fatalf("stream.Recv() = _, %v, want _, error code: %v", err, codes.Internal) + } +} + +func TestNetPipeConn(t *testing.T) { + // This test will block indefinitely if grpc writes both client and server + // prefaces without either reading from the Conn. + defer leakcheck.Check(t) + pl := testutils.NewPipeListener() + s := grpc.NewServer() + defer s.Stop() + ts := &funcServer{unaryCall: func(ctx context.Context, in *testpb.SimpleRequest) (*testpb.SimpleResponse, error) { + return &testpb.SimpleResponse{}, nil + }} + testpb.RegisterTestServiceServer(s, ts) + go s.Serve(pl) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + cc, err := grpc.DialContext(ctx, "", grpc.WithInsecure(), grpc.WithDialer(pl.Dialer())) + if err != nil { + t.Fatalf("Error creating client: %v", err) + } + defer cc.Close() + client := testpb.NewTestServiceClient(cc) + if _, err := client.UnaryCall(ctx, &testpb.SimpleRequest{}); err != nil { + t.Fatalf("UnaryCall(_) = _, %v; want _, nil", err) + } +} + +func TestLargeTimeout(t *testing.T) { + defer leakcheck.Check(t) + for _, e := range listTestEnv() { + testLargeTimeout(t, e) + } +} + +func testLargeTimeout(t *testing.T, e env) { + te := newTest(t, e) + te.declareLogNoise("Server.processUnaryRPC failed to write status") + + ts := &funcServer{} + te.startServer(ts) + defer te.tearDown() + tc := testpb.NewTestServiceClient(te.clientConn()) + + timeouts := []time.Duration{ + time.Duration(math.MaxInt64), // will be (correctly) converted to + // 2562048 hours, which overflows upon converting back to an int64 + 2562047 * time.Hour, // the largest timeout that does not overflow + } + + for i, maxTimeout := range timeouts { + ts.unaryCall = func(ctx context.Context, in *testpb.SimpleRequest) (*testpb.SimpleResponse, error) { + deadline, ok := ctx.Deadline() + timeout := deadline.Sub(time.Now()) + minTimeout := maxTimeout - 5*time.Second + if !ok || timeout < minTimeout || timeout > maxTimeout { + t.Errorf("ctx.Deadline() = (now+%v), %v; want [%v, %v], true", timeout, ok, minTimeout, maxTimeout) + return nil, status.Error(codes.OutOfRange, "deadline error") + } + return &testpb.SimpleResponse{}, nil + } + + ctx, cancel := context.WithTimeout(context.Background(), maxTimeout) + defer cancel() + + if _, err := tc.UnaryCall(ctx, &testpb.SimpleRequest{}); err != nil { + t.Errorf("case %v: UnaryCall(_) = _, %v; want _, nil", i, err) + } + } +} + +// Proxies typically send GO_AWAY followed by connection closure a minute or so later. This +// test ensures that the connection is re-created after GO_AWAY and not affected by the +// subsequent (old) connection closure. +func TestGoAwayThenClose(t *testing.T) { + defer leakcheck.Check(t) + + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) + defer cancel() + + lis1, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("Error while listening. Err: %v", err) + } + s1 := grpc.NewServer() + defer s1.Stop() + ts1 := &funcServer{ + unaryCall: func(ctx context.Context, in *testpb.SimpleRequest) (*testpb.SimpleResponse, error) { + return &testpb.SimpleResponse{}, nil + }, + fullDuplexCall: func(stream testpb.TestService_FullDuplexCallServer) error { + // Wait forever. + _, err := stream.Recv() + if err == nil { + t.Error("expected to never receive any message") + } + return err + }, + } + testpb.RegisterTestServiceServer(s1, ts1) + go s1.Serve(lis1) + + conn2Established := grpcsync.NewEvent() + lis2, err := listenWithNotifyingListener("tcp", "localhost:0", conn2Established) + if err != nil { + t.Fatalf("Error while listening. Err: %v", err) + } + s2 := grpc.NewServer() + defer s2.Stop() + conn2Ready := grpcsync.NewEvent() + ts2 := &funcServer{unaryCall: func(ctx context.Context, in *testpb.SimpleRequest) (*testpb.SimpleResponse, error) { + conn2Ready.Fire() + return &testpb.SimpleResponse{}, nil + }} + testpb.RegisterTestServiceServer(s2, ts2) + go s2.Serve(lis2) + + r, rcleanup := manual.GenerateAndRegisterManualResolver() + defer rcleanup() + r.InitialAddrs([]resolver.Address{ + {Addr: lis1.Addr().String()}, + {Addr: lis2.Addr().String()}, + }) + cc, err := grpc.DialContext(ctx, r.Scheme()+":///", grpc.WithInsecure()) + if err != nil { + t.Fatalf("Error creating client: %v", err) + } + defer cc.Close() + + client := testpb.NewTestServiceClient(cc) + + // Should go on connection 1. We use a long-lived RPC because it will cause GracefulStop to send GO_AWAY, but the + // connection doesn't get closed until the server stops and the client receives. + stream, err := client.FullDuplexCall(ctx) + if err != nil { + t.Fatalf("FullDuplexCall(_) = _, %v; want _, nil", err) + } + + // Send GO_AWAY to connection 1. + go s1.GracefulStop() + + // Wait for connection 2 to be established. + <-conn2Established.Done() + + // Close connection 1. + s1.Stop() + + // Wait for client to close. + _, err = stream.Recv() + if err == nil { + t.Fatal("expected the stream to die, but got a successful Recv") + } + + // Do a bunch of RPCs, make sure it stays stable. These should go to connection 2. + for i := 0; i < 10; i++ { + if _, err := client.UnaryCall(ctx, &testpb.SimpleRequest{}); err != nil { + t.Fatalf("UnaryCall(_) = _, %v; want _, nil", err) + } + } +} + +func listenWithNotifyingListener(network, address string, event *grpcsync.Event) (net.Listener, error) { + lis, err := net.Listen(network, address) + if err != nil { + return nil, err + } + return notifyingListener{connEstablished: event, Listener: lis}, nil +} + +type notifyingListener struct { + connEstablished *grpcsync.Event + net.Listener +} + +func (lis notifyingListener) Accept() (net.Conn, error) { + defer lis.connEstablished.Fire() + return lis.Listener.Accept() +} + +func TestRPCWaitsForResolver(t *testing.T) { + te := testServiceConfigSetup(t, tcpClearRREnv) + te.startServer(&testServer{security: tcpClearRREnv.security}) + defer te.tearDown() + r, rcleanup := manual.GenerateAndRegisterManualResolver() + defer rcleanup() + + te.resolverScheme = r.Scheme() + te.nonBlockingDial = true + cc := te.clientConn() + tc := testpb.NewTestServiceClient(cc) + + ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) + defer cancel() + // With no resolved addresses yet, this will timeout. + if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); status.Code(err) != codes.DeadlineExceeded { + t.Fatalf("TestService/EmptyCall(_, _) = _, %v, want _, %s", err, codes.DeadlineExceeded) + } + + ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + go func() { + time.Sleep(time.Second) + r.NewServiceConfig(`{ + "methodConfig": [ + { + "name": [ + { + "service": "grpc.testing.TestService", + "method": "UnaryCall" + } + ], + "maxRequestMessageBytes": 0 + } + ] + }`) + r.NewAddress([]resolver.Address{{Addr: te.srvAddr}}) + }() + // We wait a second before providing a service config and resolving + // addresses. So this will wait for that and then honor the + // maxRequestMessageBytes it contains. + if _, err := tc.UnaryCall(ctx, &testpb.SimpleRequest{ResponseType: testpb.PayloadType_UNCOMPRESSABLE}); status.Code(err) != codes.ResourceExhausted { + t.Fatalf("TestService/UnaryCall(_, _) = _, %v, want _, nil", err) + } + if got := ctx.Err(); got != nil { + t.Fatalf("ctx.Err() = %v; want nil (deadline should be set short by service config)", got) + } + if _, err := tc.UnaryCall(ctx, &testpb.SimpleRequest{}); err != nil { + t.Fatalf("TestService/UnaryCall(_, _) = _, %v, want _, nil", err) + } +} diff --git a/vendor/google.golang.org/grpc/test/go_vet/vet.go b/vendor/google.golang.org/grpc/test/go_vet/vet.go new file mode 100644 index 0000000000000000000000000000000000000000..475e8d683fc3761e18771ed7a7615ede1996d6b7 --- /dev/null +++ b/vendor/google.golang.org/grpc/test/go_vet/vet.go @@ -0,0 +1,53 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// vet checks whether files that are supposed to be built on appengine running +// Go 1.10 or earlier import an unsupported package (e.g. "unsafe", "syscall"). +package main + +import ( + "fmt" + "go/build" + "os" +) + +func main() { + fail := false + b := build.Default + b.BuildTags = []string{"appengine", "appenginevm"} + argsWithoutProg := os.Args[1:] + for _, dir := range argsWithoutProg { + p, err := b.Import(".", dir, 0) + if _, ok := err.(*build.NoGoError); ok { + continue + } else if err != nil { + fmt.Printf("build.Import failed due to %v\n", err) + fail = true + continue + } + for _, pkg := range p.Imports { + if pkg == "syscall" || pkg == "unsafe" { + fmt.Printf("Package %s/%s importing %s package without appengine build tag is NOT ALLOWED!\n", p.Dir, p.Name, pkg) + fail = true + } + } + } + if fail { + os.Exit(1) + } +} diff --git a/vendor/google.golang.org/grpc/test/gracefulstop_test.go b/vendor/google.golang.org/grpc/test/gracefulstop_test.go index 560235859a18885906e9d10f65eb1918bc17f751..be44ebb00526737dc80dfa71d25ea99df1a45dba 100644 --- a/vendor/google.golang.org/grpc/test/gracefulstop_test.go +++ b/vendor/google.golang.org/grpc/test/gracefulstop_test.go @@ -19,6 +19,7 @@ package test import ( + "context" "fmt" "io" "net" @@ -26,7 +27,6 @@ import ( "testing" "time" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/internal/leakcheck" diff --git a/vendor/google.golang.org/grpc/test/healthcheck_test.go b/vendor/google.golang.org/grpc/test/healthcheck_test.go new file mode 100644 index 0000000000000000000000000000000000000000..016ab4a620a56745aa3c2bece1a1292aa07e622d --- /dev/null +++ b/vendor/google.golang.org/grpc/test/healthcheck_test.go @@ -0,0 +1,995 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package test + +import ( + "context" + "errors" + "fmt" + "net" + "sync" + "testing" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/connectivity" + _ "google.golang.org/grpc/health" + healthgrpc "google.golang.org/grpc/health/grpc_health_v1" + healthpb "google.golang.org/grpc/health/grpc_health_v1" + "google.golang.org/grpc/internal" + "google.golang.org/grpc/internal/channelz" + "google.golang.org/grpc/internal/leakcheck" + "google.golang.org/grpc/resolver" + "google.golang.org/grpc/resolver/manual" + "google.golang.org/grpc/status" + testpb "google.golang.org/grpc/test/grpc_testing" +) + +var testHealthCheckFunc = internal.HealthCheckFunc + +func replaceHealthCheckFunc(f func(context.Context, func() (interface{}, error), func(bool), string) error) func() { + oldHcFunc := internal.HealthCheckFunc + internal.HealthCheckFunc = f + return func() { + internal.HealthCheckFunc = oldHcFunc + } +} + +func newTestHealthServer() *testHealthServer { + return newTestHealthServerWithWatchFunc(defaultWatchFunc) +} + +func newTestHealthServerWithWatchFunc(f func(s *testHealthServer, in *healthpb.HealthCheckRequest, stream healthgrpc.Health_WatchServer) error) *testHealthServer { + return &testHealthServer{ + watchFunc: f, + update: make(chan struct{}, 1), + status: make(map[string]healthpb.HealthCheckResponse_ServingStatus), + } +} + +// defaultWatchFunc will send a HealthCheckResponse to the client whenever SetServingStatus is called. +func defaultWatchFunc(s *testHealthServer, in *healthpb.HealthCheckRequest, stream healthgrpc.Health_WatchServer) error { + if in.Service != "foo" { + return status.Error(codes.FailedPrecondition, + "the defaultWatchFunc only handles request with service name to be \"foo\"") + } + var done bool + for { + select { + case <-stream.Context().Done(): + done = true + case <-s.update: + } + if done { + break + } + s.mu.Lock() + resp := &healthpb.HealthCheckResponse{ + Status: s.status[in.Service], + } + s.mu.Unlock() + stream.SendMsg(resp) + } + return nil +} + +type testHealthServer struct { + watchFunc func(s *testHealthServer, in *healthpb.HealthCheckRequest, stream healthgrpc.Health_WatchServer) error + mu sync.Mutex + status map[string]healthpb.HealthCheckResponse_ServingStatus + update chan struct{} +} + +func (s *testHealthServer) Check(ctx context.Context, in *healthpb.HealthCheckRequest) (*healthpb.HealthCheckResponse, error) { + return &healthpb.HealthCheckResponse{ + Status: healthpb.HealthCheckResponse_SERVING, + }, nil +} + +func (s *testHealthServer) Watch(in *healthpb.HealthCheckRequest, stream healthgrpc.Health_WatchServer) error { + return s.watchFunc(s, in, stream) +} + +// SetServingStatus is called when need to reset the serving status of a service +// or insert a new service entry into the statusMap. +func (s *testHealthServer) SetServingStatus(service string, status healthpb.HealthCheckResponse_ServingStatus) { + s.mu.Lock() + s.status[service] = status + select { + case <-s.update: + default: + } + s.update <- struct{}{} + s.mu.Unlock() +} + +func TestHealthCheckWatchStateChange(t *testing.T) { + defer leakcheck.Check(t) + s := grpc.NewServer() + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("failed to listen due to err: %v", err) + } + ts := newTestHealthServer() + healthgrpc.RegisterHealthServer(s, ts) + go s.Serve(lis) + defer s.Stop() + + // The table below shows the expected series of addrConn connectivity transitions when server + // updates its health status. As there's only one addrConn corresponds with the ClientConn in this + // test, we use ClientConn's connectivity state as the addrConn connectivity state. + //+------------------------------+-------------------------------------------+ + //| Health Check Returned Status | Expected addrConn Connectivity Transition | + //+------------------------------+-------------------------------------------+ + //| NOT_SERVING | ->TRANSIENT FAILURE | + //| SERVING | ->READY | + //| SERVICE_UNKNOWN | ->TRANSIENT FAILURE | + //| SERVING | ->READY | + //| UNKNOWN | ->TRANSIENT FAILURE | + //+------------------------------+-------------------------------------------+ + ts.SetServingStatus("foo", healthpb.HealthCheckResponse_NOT_SERVING) + r, rcleanup := manual.GenerateAndRegisterManualResolver() + defer rcleanup() + cc, err := grpc.Dial(r.Scheme()+":///test.server", grpc.WithInsecure(), grpc.WithBalancerName("round_robin")) + if err != nil { + t.Fatalf("dial failed due to err: %v", err) + } + defer cc.Close() + + r.NewServiceConfig(`{ + "healthCheckConfig": { + "serviceName": "foo" + } +}`) + r.NewAddress([]resolver.Address{{Addr: lis.Addr().String()}}) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + if ok := cc.WaitForStateChange(ctx, connectivity.Idle); !ok { + t.Fatal("ClientConn is still in IDLE state when the context times out.") + } + if ok := cc.WaitForStateChange(ctx, connectivity.Connecting); !ok { + t.Fatal("ClientConn is still in CONNECTING state when the context times out.") + } + if s := cc.GetState(); s != connectivity.TransientFailure { + t.Fatalf("ClientConn is in %v state, want TRANSIENT FAILURE", s) + } + + ts.SetServingStatus("foo", healthpb.HealthCheckResponse_SERVING) + if ok := cc.WaitForStateChange(ctx, connectivity.TransientFailure); !ok { + t.Fatal("ClientConn is still in TRANSIENT FAILURE state when the context times out.") + } + if s := cc.GetState(); s != connectivity.Ready { + t.Fatalf("ClientConn is in %v state, want READY", s) + } + + ts.SetServingStatus("foo", healthpb.HealthCheckResponse_SERVICE_UNKNOWN) + if ok := cc.WaitForStateChange(ctx, connectivity.Ready); !ok { + t.Fatal("ClientConn is still in READY state when the context times out.") + } + if s := cc.GetState(); s != connectivity.TransientFailure { + t.Fatalf("ClientConn is in %v state, want TRANSIENT FAILURE", s) + } + + ts.SetServingStatus("foo", healthpb.HealthCheckResponse_SERVING) + if ok := cc.WaitForStateChange(ctx, connectivity.TransientFailure); !ok { + t.Fatal("ClientConn is still in TRANSIENT FAILURE state when the context times out.") + } + if s := cc.GetState(); s != connectivity.Ready { + t.Fatalf("ClientConn is in %v state, want READY", s) + } + + ts.SetServingStatus("foo", healthpb.HealthCheckResponse_UNKNOWN) + if ok := cc.WaitForStateChange(ctx, connectivity.Ready); !ok { + t.Fatal("ClientConn is still in READY state when the context times out.") + } + if s := cc.GetState(); s != connectivity.TransientFailure { + t.Fatalf("ClientConn is in %v state, want TRANSIENT FAILURE", s) + } +} + +// If Watch returns Unimplemented, then the ClientConn should go into READY state. +func TestHealthCheckHealthServerNotRegistered(t *testing.T) { + defer leakcheck.Check(t) + s := grpc.NewServer() + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("failed to listen due to err: %v", err) + } + go s.Serve(lis) + defer s.Stop() + + r, rcleanup := manual.GenerateAndRegisterManualResolver() + defer rcleanup() + cc, err := grpc.Dial(r.Scheme()+":///test.server", grpc.WithInsecure(), grpc.WithBalancerName("round_robin")) + if err != nil { + t.Fatalf("dial failed due to err: %v", err) + } + defer cc.Close() + + r.NewServiceConfig(`{ + "healthCheckConfig": { + "serviceName": "foo" + } +}`) + r.NewAddress([]resolver.Address{{Addr: lis.Addr().String()}}) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + if ok := cc.WaitForStateChange(ctx, connectivity.Idle); !ok { + t.Fatal("ClientConn is still in IDLE state when the context times out.") + } + if ok := cc.WaitForStateChange(ctx, connectivity.Connecting); !ok { + t.Fatal("ClientConn is still in CONNECTING state when the context times out.") + } + if s := cc.GetState(); s != connectivity.Ready { + t.Fatalf("ClientConn is in %v state, want READY", s) + } +} + +// In the case of a goaway received, the health check stream should be terminated and health check +// function should exit. +func TestHealthCheckWithGoAway(t *testing.T) { + defer leakcheck.Check(t) + s := grpc.NewServer() + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("failed to listen due to err: %v", err) + } + ts := newTestHealthServer() + healthgrpc.RegisterHealthServer(s, ts) + testpb.RegisterTestServiceServer(s, &testServer{}) + go s.Serve(lis) + defer s.Stop() + ts.SetServingStatus("foo", healthpb.HealthCheckResponse_SERVING) + hcExitChan := make(chan struct{}) + testHealthCheckFuncWrapper := func(ctx context.Context, newStream func() (interface{}, error), update func(bool), service string) error { + err := testHealthCheckFunc(ctx, newStream, update, service) + close(hcExitChan) + return err + } + replace := replaceHealthCheckFunc(testHealthCheckFuncWrapper) + defer replace() + r, rcleanup := manual.GenerateAndRegisterManualResolver() + defer rcleanup() + + cc, err := grpc.Dial(r.Scheme()+":///test.server", grpc.WithInsecure(), grpc.WithBalancerName("round_robin")) + if err != nil { + t.Fatalf("dial failed due to err: %v", err) + } + defer cc.Close() + + tc := testpb.NewTestServiceClient(cc) + r.NewServiceConfig(`{ + "healthCheckConfig": { + "serviceName": "foo" + } +}`) + r.NewAddress([]resolver.Address{{Addr: lis.Addr().String()}}) + + // make some rpcs to make sure connection is working. + if err := verifyResultWithDelay(func() (bool, error) { + if _, err := tc.EmptyCall(context.Background(), &testpb.Empty{}); err != nil { + return false, fmt.Errorf("TestService/EmptyCall(_, _) = _, %v, want _, ", err) + } + return true, nil + }); err != nil { + t.Fatal(err) + } + + // the stream rpc will persist through goaway event. + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + stream, err := tc.FullDuplexCall(ctx, grpc.FailFast(false)) + if err != nil { + t.Fatalf("%v.FullDuplexCall(_) = _, %v, want ", tc, err) + } + respParam := []*testpb.ResponseParameters{{Size: 1}} + payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(1)) + if err != nil { + t.Fatal(err) + } + req := &testpb.StreamingOutputCallRequest{ + ResponseParameters: respParam, + Payload: payload, + } + if err := stream.Send(req); err != nil { + t.Fatalf("%v.Send(_) = %v, want ", stream, err) + } + if _, err := stream.Recv(); err != nil { + t.Fatalf("%v.Recv() = _, %v, want _, ", stream, err) + } + + select { + case <-hcExitChan: + t.Fatal("Health check function has exited, which is not expected.") + default: + } + + // server sends GoAway + go s.GracefulStop() + + select { + case <-hcExitChan: + case <-time.After(5 * time.Second): + t.Fatal("Health check function has not exited after 5s.") + } + + // The existing RPC should be still good to proceed. + if err := stream.Send(req); err != nil { + t.Fatalf("%v.Send(_) = %v, want ", stream, err) + } + if _, err := stream.Recv(); err != nil { + t.Fatalf("%v.Recv() = _, %v, want _, ", stream, err) + } +} + +func TestHealthCheckWithConnClose(t *testing.T) { + defer leakcheck.Check(t) + s := grpc.NewServer() + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("failed to listen due to err: %v", err) + } + ts := newTestHealthServer() + healthgrpc.RegisterHealthServer(s, ts) + testpb.RegisterTestServiceServer(s, &testServer{}) + go s.Serve(lis) + defer s.Stop() + ts.SetServingStatus("foo", healthpb.HealthCheckResponse_SERVING) + hcExitChan := make(chan struct{}) + testHealthCheckFuncWrapper := func(ctx context.Context, newStream func() (interface{}, error), update func(bool), service string) error { + err := testHealthCheckFunc(ctx, newStream, update, service) + close(hcExitChan) + return err + } + + replace := replaceHealthCheckFunc(testHealthCheckFuncWrapper) + defer replace() + r, rcleanup := manual.GenerateAndRegisterManualResolver() + defer rcleanup() + cc, err := grpc.Dial(r.Scheme()+":///test.server", grpc.WithInsecure(), grpc.WithBalancerName("round_robin")) + if err != nil { + t.Fatalf("dial failed due to err: %v", err) + } + defer cc.Close() + tc := testpb.NewTestServiceClient(cc) + + r.NewServiceConfig(`{ + "healthCheckConfig": { + "serviceName": "foo" + } +}`) + r.NewAddress([]resolver.Address{{Addr: lis.Addr().String()}}) + + // make some rpcs to make sure connection is working. + if err := verifyResultWithDelay(func() (bool, error) { + if _, err := tc.EmptyCall(context.Background(), &testpb.Empty{}); err != nil { + return false, fmt.Errorf("TestService/EmptyCall(_, _) = _, %v, want _, ", err) + } + return true, nil + }); err != nil { + t.Fatal(err) + } + + select { + case <-hcExitChan: + t.Fatal("Health check function has exited, which is not expected.") + default: + } + // server closes the connection + s.Stop() + + select { + case <-hcExitChan: + case <-time.After(5 * time.Second): + t.Fatal("Health check function has not exited after 5s.") + } +} + +// addrConn drain happens when addrConn gets torn down due to its address being no longer in the +// address list returned by the resolver. +func TestHealthCheckWithAddrConnDrain(t *testing.T) { + defer leakcheck.Check(t) + s := grpc.NewServer() + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("failed to listen due to err: %v", err) + } + ts := newTestHealthServer() + healthgrpc.RegisterHealthServer(s, ts) + testpb.RegisterTestServiceServer(s, &testServer{}) + go s.Serve(lis) + defer s.Stop() + ts.SetServingStatus("foo", healthpb.HealthCheckResponse_SERVING) + hcExitChan := make(chan struct{}) + testHealthCheckFuncWrapper := func(ctx context.Context, newStream func() (interface{}, error), update func(bool), service string) error { + err := testHealthCheckFunc(ctx, newStream, update, service) + close(hcExitChan) + return err + } + + replace := replaceHealthCheckFunc(testHealthCheckFuncWrapper) + defer replace() + r, rcleanup := manual.GenerateAndRegisterManualResolver() + defer rcleanup() + cc, err := grpc.Dial(r.Scheme()+":///test.server", grpc.WithInsecure(), grpc.WithBalancerName("round_robin")) + if err != nil { + t.Fatalf("dial failed due to err: %v", err) + } + defer cc.Close() + + tc := testpb.NewTestServiceClient(cc) + r.NewServiceConfig(`{ + "healthCheckConfig": { + "serviceName": "foo" + } +}`) + r.NewAddress([]resolver.Address{{Addr: lis.Addr().String()}}) + + // make some rpcs to make sure connection is working. + if err := verifyResultWithDelay(func() (bool, error) { + if _, err := tc.EmptyCall(context.Background(), &testpb.Empty{}); err != nil { + return false, fmt.Errorf("TestService/EmptyCall(_, _) = _, %v, want _, ", err) + } + return true, nil + }); err != nil { + t.Fatal(err) + } + + // the stream rpc will persist through goaway event. + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + stream, err := tc.FullDuplexCall(ctx, grpc.FailFast(false)) + if err != nil { + t.Fatalf("%v.FullDuplexCall(_) = _, %v, want ", tc, err) + } + respParam := []*testpb.ResponseParameters{{Size: 1}} + payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(1)) + if err != nil { + t.Fatal(err) + } + req := &testpb.StreamingOutputCallRequest{ + ResponseParameters: respParam, + Payload: payload, + } + if err := stream.Send(req); err != nil { + t.Fatalf("%v.Send(_) = %v, want ", stream, err) + } + if _, err := stream.Recv(); err != nil { + t.Fatalf("%v.Recv() = _, %v, want _, ", stream, err) + } + + select { + case <-hcExitChan: + t.Fatal("Health check function has exited, which is not expected.") + default: + } + // trigger teardown of the ac + r.NewAddress([]resolver.Address{}) + + select { + case <-hcExitChan: + case <-time.After(5 * time.Second): + t.Fatal("Health check function has not exited after 5s.") + } + + // The existing RPC should be still good to proceed. + if err := stream.Send(req); err != nil { + t.Fatalf("%v.Send(_) = %v, want ", stream, err) + } + if _, err := stream.Recv(); err != nil { + t.Fatalf("%v.Recv() = _, %v, want _, ", stream, err) + } +} + +// ClientConn close will lead to its addrConns being torn down. +func TestHealthCheckWithClientConnClose(t *testing.T) { + defer leakcheck.Check(t) + s := grpc.NewServer() + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("failed to listen due to err: %v", err) + } + ts := newTestHealthServer() + healthgrpc.RegisterHealthServer(s, ts) + testpb.RegisterTestServiceServer(s, &testServer{}) + go s.Serve(lis) + defer s.Stop() + ts.SetServingStatus("foo", healthpb.HealthCheckResponse_SERVING) + hcExitChan := make(chan struct{}) + testHealthCheckFuncWrapper := func(ctx context.Context, newStream func() (interface{}, error), update func(bool), service string) error { + err := testHealthCheckFunc(ctx, newStream, update, service) + close(hcExitChan) + return err + } + + replace := replaceHealthCheckFunc(testHealthCheckFuncWrapper) + defer replace() + r, rcleanup := manual.GenerateAndRegisterManualResolver() + defer rcleanup() + cc, err := grpc.Dial(r.Scheme()+":///test.server", grpc.WithInsecure(), grpc.WithBalancerName("round_robin")) + if err != nil { + t.Fatalf("dial failed due to err: %v", err) + } + defer cc.Close() + + tc := testpb.NewTestServiceClient(cc) + r.NewServiceConfig(`{ + "healthCheckConfig": { + "serviceName": "foo" + } +}`) + r.NewAddress([]resolver.Address{{Addr: lis.Addr().String()}}) + + // make some rpcs to make sure connection is working. + if err := verifyResultWithDelay(func() (bool, error) { + if _, err := tc.EmptyCall(context.Background(), &testpb.Empty{}); err != nil { + return false, fmt.Errorf("TestService/EmptyCall(_, _) = _, %v, want _, ", err) + } + return true, nil + }); err != nil { + t.Fatal(err) + } + + select { + case <-hcExitChan: + t.Fatal("Health check function has exited, which is not expected.") + default: + } + + // trigger addrConn teardown + cc.Close() + + select { + case <-hcExitChan: + case <-time.After(5 * time.Second): + t.Fatal("Health check function has not exited after 5s.") + } +} + +// This test is to test the logic in the createTransport after the health check function returns which +// closes the skipReset channel(since it has not been closed inside health check func) to unblock +// onGoAway/onClose goroutine. +func TestHealthCheckWithoutReportHealthCalledAddrConnShutDown(t *testing.T) { + defer leakcheck.Check(t) + s := grpc.NewServer() + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("failed to listen due to err %v", err) + } + ts := newTestHealthServerWithWatchFunc(func(s *testHealthServer, in *healthpb.HealthCheckRequest, stream healthgrpc.Health_WatchServer) error { + if in.Service != "delay" { + return status.Error(codes.FailedPrecondition, + "this special Watch function only handles request with service name to be \"delay\"") + } + // Do nothing to mock a delay of health check response from server side. + // This case is to help with the test that covers the condition that reportHealth is not + // called inside HealthCheckFunc before the func returns. + select { + case <-stream.Context().Done(): + case <-time.After(5 * time.Second): + } + return nil + }) + healthgrpc.RegisterHealthServer(s, ts) + testpb.RegisterTestServiceServer(s, &testServer{}) + go s.Serve(lis) + defer s.Stop() + ts.SetServingStatus("delay", healthpb.HealthCheckResponse_SERVING) + + hcEnterChan := make(chan struct{}) + hcExitChan := make(chan struct{}) + testHealthCheckFuncWrapper := func(ctx context.Context, newStream func() (interface{}, error), update func(bool), service string) error { + close(hcEnterChan) + err := testHealthCheckFunc(ctx, newStream, update, service) + close(hcExitChan) + return err + } + + replace := replaceHealthCheckFunc(testHealthCheckFuncWrapper) + defer replace() + r, rcleanup := manual.GenerateAndRegisterManualResolver() + defer rcleanup() + cc, err := grpc.Dial(r.Scheme()+":///test.server", grpc.WithInsecure(), grpc.WithBalancerName("round_robin")) + if err != nil { + t.Fatalf("dial failed due to err: %v", err) + } + defer cc.Close() + + // The serviceName "delay" is specially handled at server side, where response will not be sent + // back to client immediately upon receiving the request (client should receive no response until + // test ends). + r.NewServiceConfig(`{ + "healthCheckConfig": { + "serviceName": "delay" + } +}`) + r.NewAddress([]resolver.Address{{Addr: lis.Addr().String()}}) + + select { + case <-hcExitChan: + t.Fatal("Health check function has exited, which is not expected.") + default: + } + + select { + case <-hcEnterChan: + case <-time.After(5 * time.Second): + t.Fatal("Health check function has not been invoked after 5s.") + } + // trigger teardown of the ac, ac in SHUTDOWN state + r.NewAddress([]resolver.Address{}) + + // The health check func should exit without calling the reportHealth func, as server hasn't sent + // any response. + select { + case <-hcExitChan: + case <-time.After(5 * time.Second): + t.Fatal("Health check function has not exited after 5s.") + } + // The deferred leakcheck will check whether there's leaked goroutine, which is an indication + // whether we closes the skipReset channel to unblock onGoAway/onClose goroutine. +} + +// This test is to test the logic in the createTransport after the health check function returns which +// closes the allowedToReset channel(since it has not been closed inside health check func) to unblock +// onGoAway/onClose goroutine. +func TestHealthCheckWithoutReportHealthCalled(t *testing.T) { + defer leakcheck.Check(t) + s := grpc.NewServer() + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("failed to listen due to err: %v", err) + } + ts := newTestHealthServerWithWatchFunc(func(s *testHealthServer, in *healthpb.HealthCheckRequest, stream healthgrpc.Health_WatchServer) error { + if in.Service != "delay" { + return status.Error(codes.FailedPrecondition, + "this special Watch function only handles request with service name to be \"delay\"") + } + // Do nothing to mock a delay of health check response from server side. + // This case is to help with the test that covers the condition that reportHealth is not + // called inside HealthCheckFunc before the func returns. + select { + case <-stream.Context().Done(): + case <-time.After(5 * time.Second): + } + return nil + }) + healthgrpc.RegisterHealthServer(s, ts) + testpb.RegisterTestServiceServer(s, &testServer{}) + go s.Serve(lis) + defer s.Stop() + ts.SetServingStatus("delay", healthpb.HealthCheckResponse_SERVING) + + hcEnterChan := make(chan struct{}) + hcExitChan := make(chan struct{}) + testHealthCheckFuncWrapper := func(ctx context.Context, newStream func() (interface{}, error), update func(bool), service string) error { + close(hcEnterChan) + err := testHealthCheckFunc(ctx, newStream, update, service) + close(hcExitChan) + return err + } + + replace := replaceHealthCheckFunc(testHealthCheckFuncWrapper) + defer replace() + r, rcleanup := manual.GenerateAndRegisterManualResolver() + defer rcleanup() + cc, err := grpc.Dial(r.Scheme()+":///test.server", grpc.WithInsecure(), grpc.WithBalancerName("round_robin")) + if err != nil { + t.Fatalf("dial failed due to err: %v", err) + } + defer cc.Close() + + // The serviceName "delay" is specially handled at server side, where response will not be sent + // back to client immediately upon receiving the request (client should receive no response until + // test ends). + r.NewServiceConfig(`{ + "healthCheckConfig": { + "serviceName": "delay" + } +}`) + r.NewAddress([]resolver.Address{{Addr: lis.Addr().String()}}) + + select { + case <-hcExitChan: + t.Fatal("Health check function has exited, which is not expected.") + default: + } + + select { + case <-hcEnterChan: + case <-time.After(5 * time.Second): + t.Fatal("Health check function has not been invoked after 5s.") + } + // trigger transport being closed + s.Stop() + + // The health check func should exit without calling the reportHealth func, as server hasn't sent + // any response. + select { + case <-hcExitChan: + case <-time.After(5 * time.Second): + t.Fatal("Health check function has not exited after 5s.") + } + // The deferred leakcheck will check whether there's leaked goroutine, which is an indication + // whether we closes the allowedToReset channel to unblock onGoAway/onClose goroutine. +} + +func testHealthCheckDisableWithDialOption(t *testing.T, addr string) { + hcEnterChan := make(chan struct{}) + testHealthCheckFuncWrapper := func(ctx context.Context, newStream func() (interface{}, error), update func(bool), service string) error { + close(hcEnterChan) + return nil + } + + replace := replaceHealthCheckFunc(testHealthCheckFuncWrapper) + defer replace() + r, rcleanup := manual.GenerateAndRegisterManualResolver() + defer rcleanup() + cc, err := grpc.Dial(r.Scheme()+":///test.server", grpc.WithInsecure(), grpc.WithBalancerName("round_robin"), grpc.WithDisableHealthCheck()) + if err != nil { + t.Fatalf("dial failed due to err: %v", err) + } + tc := testpb.NewTestServiceClient(cc) + defer cc.Close() + r.NewServiceConfig(`{ + "healthCheckConfig": { + "serviceName": "foo" + } +}`) + r.NewAddress([]resolver.Address{{Addr: addr}}) + + // send some rpcs to make sure transport has been created and is ready for use. + if err := verifyResultWithDelay(func() (bool, error) { + if _, err := tc.EmptyCall(context.Background(), &testpb.Empty{}); err != nil { + return false, fmt.Errorf("TestService/EmptyCall(_, _) = _, %v, want _, ", err) + } + return true, nil + }); err != nil { + t.Fatal(err) + } + + select { + case <-hcEnterChan: + t.Fatal("Health check function has exited, which is not expected.") + default: + } +} + +func testHealthCheckDisableWithBalancer(t *testing.T, addr string) { + hcEnterChan := make(chan struct{}) + testHealthCheckFuncWrapper := func(ctx context.Context, newStream func() (interface{}, error), update func(bool), service string) error { + close(hcEnterChan) + return nil + } + + replace := replaceHealthCheckFunc(testHealthCheckFuncWrapper) + defer replace() + r, rcleanup := manual.GenerateAndRegisterManualResolver() + defer rcleanup() + cc, err := grpc.Dial(r.Scheme()+":///test.server", grpc.WithInsecure(), grpc.WithBalancerName("pick_first")) + if err != nil { + t.Fatalf("dial failed due to err: %v", err) + } + tc := testpb.NewTestServiceClient(cc) + defer cc.Close() + r.NewServiceConfig(`{ + "healthCheckConfig": { + "serviceName": "foo" + } +}`) + r.NewAddress([]resolver.Address{{Addr: addr}}) + + // send some rpcs to make sure transport has been created and is ready for use. + if err := verifyResultWithDelay(func() (bool, error) { + if _, err := tc.EmptyCall(context.Background(), &testpb.Empty{}); err != nil { + return false, fmt.Errorf("TestService/EmptyCall(_, _) = _, %v, want _, ", err) + } + return true, nil + }); err != nil { + t.Fatal(err) + } + + select { + case <-hcEnterChan: + t.Fatal("Health check function has started, which is not expected.") + default: + } +} + +func testHealthCheckDisableWithServiceConfig(t *testing.T, addr string) { + hcEnterChan := make(chan struct{}) + testHealthCheckFuncWrapper := func(ctx context.Context, newStream func() (interface{}, error), update func(bool), service string) error { + close(hcEnterChan) + return nil + } + + replace := replaceHealthCheckFunc(testHealthCheckFuncWrapper) + defer replace() + r, rcleanup := manual.GenerateAndRegisterManualResolver() + defer rcleanup() + cc, err := grpc.Dial(r.Scheme()+":///test.server", grpc.WithInsecure(), grpc.WithBalancerName("round_robin")) + if err != nil { + t.Fatalf("dial failed due to err: %v", err) + } + tc := testpb.NewTestServiceClient(cc) + defer cc.Close() + + r.NewAddress([]resolver.Address{{Addr: addr}}) + + // send some rpcs to make sure transport has been created and is ready for use. + if err := verifyResultWithDelay(func() (bool, error) { + if _, err := tc.EmptyCall(context.Background(), &testpb.Empty{}); err != nil { + return false, fmt.Errorf("TestService/EmptyCall(_, _) = _, %v, want _, ", err) + } + return true, nil + }); err != nil { + t.Fatal(err) + } + + select { + case <-hcEnterChan: + t.Fatal("Health check function has started, which is not expected.") + default: + } +} + +func TestHealthCheckDisable(t *testing.T) { + defer leakcheck.Check(t) + // set up server side + s := grpc.NewServer() + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("failed to listen due to err: %v", err) + } + ts := newTestHealthServer() + healthgrpc.RegisterHealthServer(s, ts) + testpb.RegisterTestServiceServer(s, &testServer{}) + go s.Serve(lis) + defer s.Stop() + ts.SetServingStatus("foo", healthpb.HealthCheckResponse_SERVING) + + // test client side disabling configuration. + testHealthCheckDisableWithDialOption(t, lis.Addr().String()) + testHealthCheckDisableWithBalancer(t, lis.Addr().String()) + testHealthCheckDisableWithServiceConfig(t, lis.Addr().String()) +} + +func TestHealthCheckChannelzCountingCallSuccess(t *testing.T) { + defer leakcheck.Check(t) + s := grpc.NewServer() + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("failed to listen due to err: %v", err) + } + ts := newTestHealthServerWithWatchFunc(func(s *testHealthServer, in *healthpb.HealthCheckRequest, stream healthgrpc.Health_WatchServer) error { + if in.Service != "channelzSuccess" { + return status.Error(codes.FailedPrecondition, + "this special Watch function only handles request with service name to be \"channelzSuccess\"") + } + return status.Error(codes.OK, "fake success") + }) + healthgrpc.RegisterHealthServer(s, ts) + testpb.RegisterTestServiceServer(s, &testServer{}) + go s.Serve(lis) + defer s.Stop() + + r, rcleanup := manual.GenerateAndRegisterManualResolver() + defer rcleanup() + cc, err := grpc.Dial(r.Scheme()+":///test.server", grpc.WithInsecure(), grpc.WithBalancerName("round_robin")) + if err != nil { + t.Fatalf("dial failed due to err: %v", err) + } + defer cc.Close() + + r.NewServiceConfig(`{ + "healthCheckConfig": { + "serviceName": "channelzSuccess" + } +}`) + r.NewAddress([]resolver.Address{{Addr: lis.Addr().String()}}) + + if err := verifyResultWithDelay(func() (bool, error) { + cm, _ := channelz.GetTopChannels(0) + if len(cm) == 0 { + return false, errors.New("channelz.GetTopChannels return 0 top channel") + } + if len(cm[0].SubChans) == 0 { + return false, errors.New("there is 0 subchannel") + } + var id int64 + for k := range cm[0].SubChans { + id = k + break + } + scm := channelz.GetSubChannel(id) + if scm == nil || scm.ChannelData == nil { + return false, errors.New("nil subchannel metric or nil subchannel metric ChannelData returned") + } + // exponential backoff retry may result in more than one health check call. + if scm.ChannelData.CallsStarted > 0 && scm.ChannelData.CallsSucceeded > 0 && scm.ChannelData.CallsFailed == 0 { + return true, nil + } + return false, fmt.Errorf("got %d CallsStarted, %d CallsSucceeded, want >0 >0", scm.ChannelData.CallsStarted, scm.ChannelData.CallsSucceeded) + }); err != nil { + t.Fatal(err) + } +} + +func TestHealthCheckChannelzCountingCallFailure(t *testing.T) { + defer leakcheck.Check(t) + s := grpc.NewServer() + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("failed to listen due to err: %v", err) + } + ts := newTestHealthServerWithWatchFunc(func(s *testHealthServer, in *healthpb.HealthCheckRequest, stream healthgrpc.Health_WatchServer) error { + if in.Service != "channelzFailure" { + return status.Error(codes.FailedPrecondition, + "this special Watch function only handles request with service name to be \"channelzFailure\"") + } + return status.Error(codes.Internal, "fake failure") + }) + healthgrpc.RegisterHealthServer(s, ts) + testpb.RegisterTestServiceServer(s, &testServer{}) + go s.Serve(lis) + defer s.Stop() + + r, rcleanup := manual.GenerateAndRegisterManualResolver() + defer rcleanup() + cc, err := grpc.Dial(r.Scheme()+":///test.server", grpc.WithInsecure(), grpc.WithBalancerName("round_robin")) + if err != nil { + t.Fatalf("dial failed due to err: %v", err) + } + defer cc.Close() + + r.NewServiceConfig(`{ + "healthCheckConfig": { + "serviceName": "channelzFailure" + } +}`) + r.NewAddress([]resolver.Address{{Addr: lis.Addr().String()}}) + + if err := verifyResultWithDelay(func() (bool, error) { + cm, _ := channelz.GetTopChannels(0) + if len(cm) == 0 { + return false, errors.New("channelz.GetTopChannels return 0 top channel") + } + if len(cm[0].SubChans) == 0 { + return false, errors.New("there is 0 subchannel") + } + var id int64 + for k := range cm[0].SubChans { + id = k + break + } + scm := channelz.GetSubChannel(id) + if scm == nil || scm.ChannelData == nil { + return false, errors.New("nil subchannel metric or nil subchannel metric ChannelData returned") + } + // exponential backoff retry may result in more than one health check call. + if scm.ChannelData.CallsStarted > 0 && scm.ChannelData.CallsFailed > 0 && scm.ChannelData.CallsSucceeded == 0 { + return true, nil + } + return false, fmt.Errorf("got %d CallsStarted, %d CallsFailed, want >0, >0", scm.ChannelData.CallsStarted, scm.ChannelData.CallsFailed) + }); err != nil { + t.Fatal(err) + } +} diff --git a/vendor/google.golang.org/grpc/test/rawConnWrapper.go b/vendor/google.golang.org/grpc/test/rawConnWrapper.go index 8d4ee020334f11ac83ead798a18f51b37300ed72..5d991cf013ac2f12bc6bb60e055296fa606e56e2 100644 --- a/vendor/google.golang.org/grpc/test/rawConnWrapper.go +++ b/vendor/google.golang.org/grpc/test/rawConnWrapper.go @@ -161,24 +161,24 @@ func (rcw *rawConnWrapper) greet() error { func (rcw *rawConnWrapper) writePreface() error { n, err := rcw.cc.Write([]byte(http2.ClientPreface)) if err != nil { - return fmt.Errorf("Error writing client preface: %v", err) + return fmt.Errorf("error writing client preface: %v", err) } if n != len(http2.ClientPreface) { - return fmt.Errorf("Writing client preface, wrote %d bytes; want %d", n, len(http2.ClientPreface)) + return fmt.Errorf("writing client preface, wrote %d bytes; want %d", n, len(http2.ClientPreface)) } return nil } func (rcw *rawConnWrapper) writeInitialSettings() error { if err := rcw.fr.WriteSettings(); err != nil { - return fmt.Errorf("Error writing initial SETTINGS frame from client to server: %v", err) + return fmt.Errorf("error writing initial SETTINGS frame from client to server: %v", err) } return nil } func (rcw *rawConnWrapper) writeSettingsAck() error { if err := rcw.fr.WriteSettingsAck(); err != nil { - return fmt.Errorf("Error writing ACK of server's SETTINGS: %v", err) + return fmt.Errorf("error writing ACK of server's SETTINGS: %v", err) } return nil } @@ -186,7 +186,7 @@ func (rcw *rawConnWrapper) writeSettingsAck() error { func (rcw *rawConnWrapper) wantSettings() (*http2.SettingsFrame, error) { f, err := rcw.readFrame() if err != nil { - return nil, fmt.Errorf("Error while expecting a SETTINGS frame: %v", err) + return nil, fmt.Errorf("error while expecting a SETTINGS frame: %v", err) } sf, ok := f.(*http2.SettingsFrame) if !ok { @@ -202,10 +202,10 @@ func (rcw *rawConnWrapper) wantSettingsAck() error { } sf, ok := f.(*http2.SettingsFrame) if !ok { - return fmt.Errorf("Wanting a settings ACK, received a %T", f) + return fmt.Errorf("wanting a settings ACK, received a %T", f) } if !sf.IsAck() { - return fmt.Errorf("Settings Frame didn't have ACK set") + return fmt.Errorf("settings Frame didn't have ACK set") } return nil } @@ -304,42 +304,42 @@ func (rcw *rawConnWrapper) writeHeadersGRPC(streamID uint32, path string) { func (rcw *rawConnWrapper) writeHeaders(p http2.HeadersFrameParam) error { if err := rcw.fr.WriteHeaders(p); err != nil { - return fmt.Errorf("Error writing HEADERS: %v", err) + return fmt.Errorf("error writing HEADERS: %v", err) } return nil } func (rcw *rawConnWrapper) writeData(streamID uint32, endStream bool, data []byte) error { if err := rcw.fr.WriteData(streamID, endStream, data); err != nil { - return fmt.Errorf("Error writing DATA: %v", err) + return fmt.Errorf("error writing DATA: %v", err) } return nil } func (rcw *rawConnWrapper) writeRSTStream(streamID uint32, code http2.ErrCode) error { if err := rcw.fr.WriteRSTStream(streamID, code); err != nil { - return fmt.Errorf("Error writing RST_STREAM: %v", err) + return fmt.Errorf("error writing RST_STREAM: %v", err) } return nil } func (rcw *rawConnWrapper) writeDataPadded(streamID uint32, endStream bool, data, padding []byte) error { if err := rcw.fr.WriteDataPadded(streamID, endStream, data, padding); err != nil { - return fmt.Errorf("Error writing DATA with padding: %v", err) + return fmt.Errorf("error writing DATA with padding: %v", err) } return nil } func (rcw *rawConnWrapper) writeGoAway(maxStreamID uint32, code http2.ErrCode, debugData []byte) error { if err := rcw.fr.WriteGoAway(maxStreamID, code, debugData); err != nil { - return fmt.Errorf("Error writing GoAway: %v", err) + return fmt.Errorf("error writing GoAway: %v", err) } return nil } func (rcw *rawConnWrapper) writeRawFrame(t http2.FrameType, flags http2.Flags, streamID uint32, payload []byte) error { if err := rcw.fr.WriteRawFrame(t, flags, streamID, payload); err != nil { - return fmt.Errorf("Error writing Raw Frame: %v", err) + return fmt.Errorf("error writing Raw Frame: %v", err) } return nil } diff --git a/vendor/google.golang.org/grpc/test/retry_test.go b/vendor/google.golang.org/grpc/test/retry_test.go new file mode 100644 index 0000000000000000000000000000000000000000..b9a4acff51e39d17afc9b7f10ed847601d75662b --- /dev/null +++ b/vendor/google.golang.org/grpc/test/retry_test.go @@ -0,0 +1,551 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package test + +import ( + "context" + "fmt" + "io" + "os" + "reflect" + "strconv" + "strings" + "testing" + "time" + + "github.com/golang/protobuf/proto" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/internal/envconfig" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + testpb "google.golang.org/grpc/test/grpc_testing" +) + +func enableRetry() func() { + old := envconfig.Retry + envconfig.Retry = true + return func() { envconfig.Retry = old } +} + +func TestRetryUnary(t *testing.T) { + defer enableRetry()() + i := -1 + ss := &stubServer{ + emptyCall: func(context.Context, *testpb.Empty) (*testpb.Empty, error) { + i++ + switch i { + case 0, 2, 5: + return &testpb.Empty{}, nil + case 6, 8, 11: + return nil, status.New(codes.Internal, "non-retryable error").Err() + } + return nil, status.New(codes.AlreadyExists, "retryable error").Err() + }, + } + if err := ss.Start([]grpc.ServerOption{}); err != nil { + t.Fatalf("Error starting endpoint server: %v", err) + } + defer ss.Stop() + ss.r.NewServiceConfig(`{ + "methodConfig": [{ + "name": [{"service": "grpc.testing.TestService"}], + "waitForReady": true, + "retryPolicy": { + "MaxAttempts": 4, + "InitialBackoff": ".01s", + "MaxBackoff": ".01s", + "BackoffMultiplier": 1.0, + "RetryableStatusCodes": [ "ALREADY_EXISTS" ] + } + }]}`) + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + for { + if ctx.Err() != nil { + t.Fatalf("Timed out waiting for service config update") + } + if ss.cc.GetMethodConfig("/grpc.testing.TestService/EmptyCall").WaitForReady != nil { + break + } + time.Sleep(time.Millisecond) + } + cancel() + + testCases := []struct { + code codes.Code + count int + }{ + {codes.OK, 0}, + {codes.OK, 2}, + {codes.OK, 5}, + {codes.Internal, 6}, + {codes.Internal, 8}, + {codes.Internal, 11}, + {codes.AlreadyExists, 15}, + } + for _, tc := range testCases { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + _, err := ss.client.EmptyCall(ctx, &testpb.Empty{}) + cancel() + if status.Code(err) != tc.code { + t.Fatalf("EmptyCall(_, _) = _, %v; want _, ", err, tc.code) + } + if i != tc.count { + t.Fatalf("i = %v; want %v", i, tc.count) + } + } +} + +func TestRetryDisabledByDefault(t *testing.T) { + if strings.EqualFold(os.Getenv("GRPC_GO_RETRY"), "on") { + return + } + i := -1 + ss := &stubServer{ + emptyCall: func(context.Context, *testpb.Empty) (*testpb.Empty, error) { + i++ + switch i { + case 0: + return nil, status.New(codes.AlreadyExists, "retryable error").Err() + } + return &testpb.Empty{}, nil + }, + } + if err := ss.Start([]grpc.ServerOption{}); err != nil { + t.Fatalf("Error starting endpoint server: %v", err) + } + defer ss.Stop() + ss.r.NewServiceConfig(`{ + "methodConfig": [{ + "name": [{"service": "grpc.testing.TestService"}], + "waitForReady": true, + "retryPolicy": { + "MaxAttempts": 4, + "InitialBackoff": ".01s", + "MaxBackoff": ".01s", + "BackoffMultiplier": 1.0, + "RetryableStatusCodes": [ "ALREADY_EXISTS" ] + } + }]}`) + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + for { + if ctx.Err() != nil { + t.Fatalf("Timed out waiting for service config update") + } + if ss.cc.GetMethodConfig("/grpc.testing.TestService/EmptyCall").WaitForReady != nil { + break + } + time.Sleep(time.Millisecond) + } + cancel() + + testCases := []struct { + code codes.Code + count int + }{ + {codes.AlreadyExists, 0}, + } + for _, tc := range testCases { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + _, err := ss.client.EmptyCall(ctx, &testpb.Empty{}) + cancel() + if status.Code(err) != tc.code { + t.Fatalf("EmptyCall(_, _) = _, %v; want _, ", err, tc.code) + } + if i != tc.count { + t.Fatalf("i = %v; want %v", i, tc.count) + } + } +} + +func TestRetryThrottling(t *testing.T) { + defer enableRetry()() + i := -1 + ss := &stubServer{ + emptyCall: func(context.Context, *testpb.Empty) (*testpb.Empty, error) { + i++ + switch i { + case 0, 3, 6, 10, 11, 12, 13, 14, 16, 18: + return &testpb.Empty{}, nil + } + return nil, status.New(codes.Unavailable, "retryable error").Err() + }, + } + if err := ss.Start([]grpc.ServerOption{}); err != nil { + t.Fatalf("Error starting endpoint server: %v", err) + } + defer ss.Stop() + ss.r.NewServiceConfig(`{ + "methodConfig": [{ + "name": [{"service": "grpc.testing.TestService"}], + "waitForReady": true, + "retryPolicy": { + "MaxAttempts": 4, + "InitialBackoff": ".01s", + "MaxBackoff": ".01s", + "BackoffMultiplier": 1.0, + "RetryableStatusCodes": [ "UNAVAILABLE" ] + } + }], + "retryThrottling": { + "maxTokens": 10, + "tokenRatio": 0.5 + } + }`) + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + for { + if ctx.Err() != nil { + t.Fatalf("Timed out waiting for service config update") + } + if ss.cc.GetMethodConfig("/grpc.testing.TestService/EmptyCall").WaitForReady != nil { + break + } + time.Sleep(time.Millisecond) + } + cancel() + + testCases := []struct { + code codes.Code + count int + }{ + {codes.OK, 0}, // tokens = 10 + {codes.OK, 3}, // tokens = 8.5 (10 - 2 failures + 0.5 success) + {codes.OK, 6}, // tokens = 6 + {codes.Unavailable, 8}, // tokens = 5 -- first attempt is retried; second aborted. + {codes.Unavailable, 9}, // tokens = 4 + {codes.OK, 10}, // tokens = 4.5 + {codes.OK, 11}, // tokens = 5 + {codes.OK, 12}, // tokens = 5.5 + {codes.OK, 13}, // tokens = 6 + {codes.OK, 14}, // tokens = 6.5 + {codes.OK, 16}, // tokens = 5.5 + {codes.Unavailable, 17}, // tokens = 4.5 + } + for _, tc := range testCases { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + _, err := ss.client.EmptyCall(ctx, &testpb.Empty{}) + cancel() + if status.Code(err) != tc.code { + t.Errorf("EmptyCall(_, _) = _, %v; want _, ", err, tc.code) + } + if i != tc.count { + t.Errorf("i = %v; want %v", i, tc.count) + } + } +} + +func TestRetryStreaming(t *testing.T) { + defer enableRetry()() + req := func(b byte) *testpb.StreamingOutputCallRequest { + return &testpb.StreamingOutputCallRequest{Payload: &testpb.Payload{Body: []byte{b}}} + } + res := func(b byte) *testpb.StreamingOutputCallResponse { + return &testpb.StreamingOutputCallResponse{Payload: &testpb.Payload{Body: []byte{b}}} + } + + largePayload, _ := newPayload(testpb.PayloadType_COMPRESSABLE, 500) + + type serverOp func(stream testpb.TestService_FullDuplexCallServer) error + type clientOp func(stream testpb.TestService_FullDuplexCallClient) error + + // Server Operations + sAttempts := func(n int) serverOp { + return func(stream testpb.TestService_FullDuplexCallServer) error { + const key = "grpc-previous-rpc-attempts" + md, ok := metadata.FromIncomingContext(stream.Context()) + if !ok { + return status.Errorf(codes.Internal, "server: no header metadata received") + } + if got := md[key]; len(got) != 1 || got[0] != strconv.Itoa(n) { + return status.Errorf(codes.Internal, "server: metadata = %v; want ", md, key, n) + } + return nil + } + } + sReq := func(b byte) serverOp { + return func(stream testpb.TestService_FullDuplexCallServer) error { + want := req(b) + if got, err := stream.Recv(); err != nil || !proto.Equal(got, want) { + return status.Errorf(codes.Internal, "server: Recv() = %v, %v; want %v, ", got, err, want) + } + return nil + } + } + sReqPayload := func(p *testpb.Payload) serverOp { + return func(stream testpb.TestService_FullDuplexCallServer) error { + want := &testpb.StreamingOutputCallRequest{Payload: p} + if got, err := stream.Recv(); err != nil || !proto.Equal(got, want) { + return status.Errorf(codes.Internal, "server: Recv() = %v, %v; want %v, ", got, err, want) + } + return nil + } + } + sRes := func(b byte) serverOp { + return func(stream testpb.TestService_FullDuplexCallServer) error { + msg := res(b) + if err := stream.Send(msg); err != nil { + return status.Errorf(codes.Internal, "server: Send(%v) = %v; want ", msg, err) + } + return nil + } + } + sErr := func(c codes.Code) serverOp { + return func(stream testpb.TestService_FullDuplexCallServer) error { + return status.New(c, "").Err() + } + } + sCloseSend := func() serverOp { + return func(stream testpb.TestService_FullDuplexCallServer) error { + if msg, err := stream.Recv(); msg != nil || err != io.EOF { + return status.Errorf(codes.Internal, "server: Recv() = %v, %v; want , io.EOF", msg, err) + } + return nil + } + } + sPushback := func(s string) serverOp { + return func(stream testpb.TestService_FullDuplexCallServer) error { + stream.SetTrailer(metadata.MD{"grpc-retry-pushback-ms": []string{s}}) + return nil + } + } + + // Client Operations + cReq := func(b byte) clientOp { + return func(stream testpb.TestService_FullDuplexCallClient) error { + msg := req(b) + if err := stream.Send(msg); err != nil { + return fmt.Errorf("client: Send(%v) = %v; want ", msg, err) + } + return nil + } + } + cReqPayload := func(p *testpb.Payload) clientOp { + return func(stream testpb.TestService_FullDuplexCallClient) error { + msg := &testpb.StreamingOutputCallRequest{Payload: p} + if err := stream.Send(msg); err != nil { + return fmt.Errorf("client: Send(%v) = %v; want ", msg, err) + } + return nil + } + } + cRes := func(b byte) clientOp { + return func(stream testpb.TestService_FullDuplexCallClient) error { + want := res(b) + if got, err := stream.Recv(); err != nil || !proto.Equal(got, want) { + return fmt.Errorf("client: Recv() = %v, %v; want %v, ", got, err, want) + } + return nil + } + } + cErr := func(c codes.Code) clientOp { + return func(stream testpb.TestService_FullDuplexCallClient) error { + want := status.New(c, "").Err() + if c == codes.OK { + want = io.EOF + } + res, err := stream.Recv() + if res != nil || + ((err == nil) != (want == nil)) || + (want != nil && !reflect.DeepEqual(err, want)) { + return fmt.Errorf("client: Recv() = %v, %v; want , %v", res, err, want) + } + return nil + } + } + cCloseSend := func() clientOp { + return func(stream testpb.TestService_FullDuplexCallClient) error { + if err := stream.CloseSend(); err != nil { + return fmt.Errorf("client: CloseSend() = %v; want ", err) + } + return nil + } + } + var curTime time.Time + cGetTime := func() clientOp { + return func(_ testpb.TestService_FullDuplexCallClient) error { + curTime = time.Now() + return nil + } + } + cCheckElapsed := func(d time.Duration) clientOp { + return func(_ testpb.TestService_FullDuplexCallClient) error { + if elapsed := time.Since(curTime); elapsed < d { + return fmt.Errorf("Elapsed time: %v; want >= %v", elapsed, d) + } + return nil + } + } + cHdr := func() clientOp { + return func(stream testpb.TestService_FullDuplexCallClient) error { + _, err := stream.Header() + return err + } + } + cCtx := func() clientOp { + return func(stream testpb.TestService_FullDuplexCallClient) error { + stream.Context() + return nil + } + } + + testCases := []struct { + desc string + serverOps []serverOp + clientOps []clientOp + }{{ + desc: "Non-retryable error code", + serverOps: []serverOp{sReq(1), sErr(codes.Internal)}, + clientOps: []clientOp{cReq(1), cErr(codes.Internal)}, + }, { + desc: "One retry necessary", + serverOps: []serverOp{sReq(1), sErr(codes.Unavailable), sReq(1), sAttempts(1), sRes(1)}, + clientOps: []clientOp{cReq(1), cRes(1), cErr(codes.OK)}, + }, { + desc: "Exceed max attempts (4); check attempts header on server", + serverOps: []serverOp{ + sReq(1), sErr(codes.Unavailable), + sReq(1), sAttempts(1), sErr(codes.Unavailable), + sAttempts(2), sReq(1), sErr(codes.Unavailable), + sAttempts(3), sReq(1), sErr(codes.Unavailable), + }, + clientOps: []clientOp{cReq(1), cErr(codes.Unavailable)}, + }, { + desc: "Multiple requests", + serverOps: []serverOp{ + sReq(1), sReq(2), sErr(codes.Unavailable), + sReq(1), sReq(2), sRes(5), + }, + clientOps: []clientOp{cReq(1), cReq(2), cRes(5), cErr(codes.OK)}, + }, { + desc: "Multiple successive requests", + serverOps: []serverOp{ + sReq(1), sErr(codes.Unavailable), + sReq(1), sReq(2), sErr(codes.Unavailable), + sReq(1), sReq(2), sReq(3), sRes(5), + }, + clientOps: []clientOp{cReq(1), cReq(2), cReq(3), cRes(5), cErr(codes.OK)}, + }, { + desc: "No retry after receiving", + serverOps: []serverOp{ + sReq(1), sErr(codes.Unavailable), + sReq(1), sRes(3), sErr(codes.Unavailable), + }, + clientOps: []clientOp{cReq(1), cRes(3), cErr(codes.Unavailable)}, + }, { + desc: "No retry after header", + serverOps: []serverOp{sReq(1), sErr(codes.Unavailable)}, + clientOps: []clientOp{cReq(1), cHdr(), cErr(codes.Unavailable)}, + }, { + desc: "No retry after context", + serverOps: []serverOp{sReq(1), sErr(codes.Unavailable)}, + clientOps: []clientOp{cReq(1), cCtx(), cErr(codes.Unavailable)}, + }, { + desc: "Replaying close send", + serverOps: []serverOp{ + sReq(1), sReq(2), sCloseSend(), sErr(codes.Unavailable), + sReq(1), sReq(2), sCloseSend(), sRes(1), sRes(3), sRes(5), + }, + clientOps: []clientOp{cReq(1), cReq(2), cCloseSend(), cRes(1), cRes(3), cRes(5), cErr(codes.OK)}, + }, { + desc: "Negative server pushback - no retry", + serverOps: []serverOp{sReq(1), sPushback("-1"), sErr(codes.Unavailable)}, + clientOps: []clientOp{cReq(1), cErr(codes.Unavailable)}, + }, { + desc: "Non-numeric server pushback - no retry", + serverOps: []serverOp{sReq(1), sPushback("xxx"), sErr(codes.Unavailable)}, + clientOps: []clientOp{cReq(1), cErr(codes.Unavailable)}, + }, { + desc: "Multiple server pushback values - no retry", + serverOps: []serverOp{sReq(1), sPushback("100"), sPushback("10"), sErr(codes.Unavailable)}, + clientOps: []clientOp{cReq(1), cErr(codes.Unavailable)}, + }, { + desc: "1s server pushback - delayed retry", + serverOps: []serverOp{sReq(1), sPushback("1000"), sErr(codes.Unavailable), sReq(1), sRes(2)}, + clientOps: []clientOp{cGetTime(), cReq(1), cRes(2), cCheckElapsed(time.Second), cErr(codes.OK)}, + }, { + desc: "Overflowing buffer - no retry", + serverOps: []serverOp{sReqPayload(largePayload), sErr(codes.Unavailable)}, + clientOps: []clientOp{cReqPayload(largePayload), cErr(codes.Unavailable)}, + }} + + var serverOpIter int + var serverOps []serverOp + ss := &stubServer{ + fullDuplexCall: func(stream testpb.TestService_FullDuplexCallServer) error { + for serverOpIter < len(serverOps) { + op := serverOps[serverOpIter] + serverOpIter++ + if err := op(stream); err != nil { + return err + } + } + return nil + }, + } + if err := ss.Start([]grpc.ServerOption{}, grpc.WithDefaultCallOptions(grpc.MaxRetryRPCBufferSize(200))); err != nil { + t.Fatalf("Error starting endpoint server: %v", err) + } + defer ss.Stop() + ss.r.NewServiceConfig(`{ + "methodConfig": [{ + "name": [{"service": "grpc.testing.TestService"}], + "waitForReady": true, + "retryPolicy": { + "MaxAttempts": 4, + "InitialBackoff": ".01s", + "MaxBackoff": ".01s", + "BackoffMultiplier": 1.0, + "RetryableStatusCodes": [ "UNAVAILABLE" ] + } + }]}`) + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + for { + if ctx.Err() != nil { + t.Fatalf("Timed out waiting for service config update") + } + if ss.cc.GetMethodConfig("/grpc.testing.TestService/FullDuplexCall").WaitForReady != nil { + break + } + time.Sleep(time.Millisecond) + } + cancel() + + for _, tc := range testCases { + func() { + serverOpIter = 0 + serverOps = tc.serverOps + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + stream, err := ss.client.FullDuplexCall(ctx) + if err != nil { + t.Fatalf("%v: Error while creating stream: %v", tc.desc, err) + } + for _, op := range tc.clientOps { + if err := op(stream); err != nil { + t.Errorf("%v: %v", tc.desc, err) + break + } + } + if serverOpIter != len(serverOps) { + t.Errorf("%v: serverOpIter = %v; want %v", tc.desc, serverOpIter, len(serverOps)) + } + }() + } +} diff --git a/vendor/google.golang.org/grpc/test/tools/tools.go b/vendor/google.golang.org/grpc/test/tools/tools.go new file mode 100644 index 0000000000000000000000000000000000000000..511dc2534462ddfc841d2b0ab24c986bccfc0770 --- /dev/null +++ b/vendor/google.golang.org/grpc/test/tools/tools.go @@ -0,0 +1,34 @@ +// +build tools + +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// This package exists to cause `go mod` and `go get` to believe these tools +// are dependencies, even though they are not runtime dependencies of any grpc +// package. This means they will appear in our `go.mod` file, but will not be +// a part of the build. + +package tools + +import ( + _ "github.com/client9/misspell/cmd/misspell" + _ "github.com/golang/protobuf/protoc-gen-go" + _ "golang.org/x/lint/golint" + _ "golang.org/x/tools/cmd/goimports" + _ "honnef.co/go/tools/cmd/staticcheck" +) diff --git a/vendor/google.golang.org/grpc/testdata/testdata.go b/vendor/google.golang.org/grpc/testdata/testdata.go index 5609b19b3a503ff83d75d27f972d874a2c8e5364..c7d2481c4a0367be572ec24dd2b76b766968bfc7 100644 --- a/vendor/google.golang.org/grpc/testdata/testdata.go +++ b/vendor/google.golang.org/grpc/testdata/testdata.go @@ -18,11 +18,18 @@ package testdata import ( - "log" - "os" "path/filepath" + "runtime" ) +// basepath is the root directory of this package. +var basepath string + +func init() { + _, currentFile, _, _ := runtime.Caller(0) + basepath = filepath.Dir(currentFile) +} + // Path returns the absolute path the given relative file or directory path, // relative to the google.golang.org/grpc/testdata directory in the user's GOPATH. // If rel is already absolute, it is returned unmodified. @@ -31,33 +38,5 @@ func Path(rel string) string { return rel } - v, err := goPackagePath("google.golang.org/grpc/testdata") - if err != nil { - log.Fatalf("Error finding google.golang.org/grpc/testdata directory: %v", err) - } - - return filepath.Join(v, rel) -} - -func goPackagePath(pkg string) (path string, err error) { - gp := os.Getenv("GOPATH") - if gp == "" { - return path, os.ErrNotExist - } - - for _, p := range filepath.SplitList(gp) { - dir := filepath.Join(p, "src", filepath.FromSlash(pkg)) - fi, err := os.Stat(dir) - if os.IsNotExist(err) { - continue - } - if err != nil { - return "", err - } - if !fi.IsDir() { - continue - } - return dir, nil - } - return path, os.ErrNotExist + return filepath.Join(basepath, rel) } diff --git a/vendor/google.golang.org/grpc/transport/go16.go b/vendor/google.golang.org/grpc/transport/go16.go deleted file mode 100644 index 5babcf9b87706314e70471afe86811d342b988ad..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/transport/go16.go +++ /dev/null @@ -1,51 +0,0 @@ -// +build go1.6,!go1.7 - -/* - * - * Copyright 2016 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package transport - -import ( - "net" - "net/http" - - "google.golang.org/grpc/codes" - - "golang.org/x/net/context" -) - -// dialContext connects to the address on the named network. -func dialContext(ctx context.Context, network, address string) (net.Conn, error) { - return (&net.Dialer{Cancel: ctx.Done()}).Dial(network, address) -} - -// ContextErr converts the error from context package into a StreamError. -func ContextErr(err error) StreamError { - switch err { - case context.DeadlineExceeded: - return streamErrorf(codes.DeadlineExceeded, "%v", err) - case context.Canceled: - return streamErrorf(codes.Canceled, "%v", err) - } - return streamErrorf(codes.Internal, "Unexpected error from context packet: %v", err) -} - -// contextFromRequest returns a background context. -func contextFromRequest(r *http.Request) context.Context { - return context.Background() -} diff --git a/vendor/google.golang.org/grpc/transport/go17.go b/vendor/google.golang.org/grpc/transport/go17.go deleted file mode 100644 index b7fa6bdb9ca2962094d7bc6bb82ccad836d374df..0000000000000000000000000000000000000000 --- a/vendor/google.golang.org/grpc/transport/go17.go +++ /dev/null @@ -1,52 +0,0 @@ -// +build go1.7 - -/* - * - * Copyright 2016 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package transport - -import ( - "context" - "net" - "net/http" - - "google.golang.org/grpc/codes" - - netctx "golang.org/x/net/context" -) - -// dialContext connects to the address on the named network. -func dialContext(ctx context.Context, network, address string) (net.Conn, error) { - return (&net.Dialer{}).DialContext(ctx, network, address) -} - -// ContextErr converts the error from context package into a StreamError. -func ContextErr(err error) StreamError { - switch err { - case context.DeadlineExceeded, netctx.DeadlineExceeded: - return streamErrorf(codes.DeadlineExceeded, "%v", err) - case context.Canceled, netctx.Canceled: - return streamErrorf(codes.Canceled, "%v", err) - } - return streamErrorf(codes.Internal, "Unexpected error from context packet: %v", err) -} - -// contextFromRequest returns a context from the HTTP Request. -func contextFromRequest(r *http.Request) context.Context { - return r.Context() -} diff --git a/vendor/google.golang.org/grpc/version.go b/vendor/google.golang.org/grpc/version.go index 7f124fbd5321ecadac242618f0a9d28ad7daaf73..260f27c88040e5963f30ce45db908181bf393439 100644 --- a/vendor/google.golang.org/grpc/version.go +++ b/vendor/google.golang.org/grpc/version.go @@ -19,4 +19,4 @@ package grpc // Version is the current grpc version. -const Version = "1.13.0" +const Version = "1.17.0" diff --git a/vendor/google.golang.org/grpc/vet.sh b/vendor/google.golang.org/grpc/vet.sh index 079bc2896d7b0f56194363ce4742d2a9e09891c4..94d3d54e2fbb427a30c9d3e6714c876179036b8e 100755 --- a/vendor/google.golang.org/grpc/vet.sh +++ b/vendor/google.golang.org/grpc/vet.sh @@ -13,24 +13,50 @@ die() { exit 1 } -PATH="$GOPATH/bin:$GOROOT/bin:$PATH" +# Check to make sure it's safe to modify the user's git repo. +if git status --porcelain | read; then + die "Uncommitted or untracked files found; commit changes first" +fi -# Check proto in manual runs or cron runs. -if [[ "$TRAVIS" != "true" || "$TRAVIS_EVENT_TYPE" = "cron" ]]; then - check_proto="true" +if [[ -d "${GOPATH}/src" ]]; then + die "\${GOPATH}/src (${GOPATH}/src) exists; this script will delete it." fi -if [ "$1" = "-install" ]; then - go get -d \ - google.golang.org/grpc/... - go get -u \ - github.com/golang/lint/golint \ - golang.org/x/tools/cmd/goimports \ - honnef.co/go/tools/cmd/staticcheck \ - github.com/client9/misspell/cmd/misspell \ - github.com/golang/protobuf/protoc-gen-go - if [[ "$check_proto" = "true" ]]; then - if [[ "$TRAVIS" = "true" ]]; then +# Undo any edits made by this script. +cleanup() { + rm -rf "${GOPATH}/src" + git reset --hard HEAD +} +trap cleanup EXIT + +fail_on_output() { + tee /dev/stderr | (! read) +} + +PATH="${GOPATH}/bin:${GOROOT}/bin:${PATH}" + +if [[ "$1" = "-install" ]]; then + # Check for module support + if go help mod >& /dev/null; then + go install \ + golang.org/x/lint/golint \ + golang.org/x/tools/cmd/goimports \ + honnef.co/go/tools/cmd/staticcheck \ + github.com/client9/misspell/cmd/misspell \ + github.com/golang/protobuf/protoc-gen-go + else + # Ye olde `go get` incantation. + # Note: this gets the latest version of all tools (vs. the pinned versions + # with Go modules). + go get -u \ + golang.org/x/lint/golint \ + golang.org/x/tools/cmd/goimports \ + honnef.co/go/tools/cmd/staticcheck \ + github.com/client9/misspell/cmd/misspell \ + github.com/golang/protobuf/protoc-gen-go + fi + if [[ -z "${VET_SKIP_PROTO}" ]]; then + if [[ "${TRAVIS}" = "true" ]]; then PROTOBUF_VERSION=3.3.0 PROTOC_FILENAME=protoc-${PROTOBUF_VERSION}-linux-x86_64.zip pushd /home/travis @@ -47,48 +73,64 @@ elif [[ "$#" -ne 0 ]]; then die "Unknown argument(s): $*" fi -# TODO: Remove this check and the mangling below once "context" is imported -# directly. -if git status --porcelain | read; then - die "Uncommitted or untracked files found; commit changes first" -fi +# - Ensure all source files contain a copyright message. +git ls-files "*.go" | xargs grep -L "\(Copyright [0-9]\{4,\} gRPC authors\)\|DO NOT EDIT" 2>&1 | fail_on_output -git ls-files "*.go" | xargs grep -L "\(Copyright [0-9]\{4,\} gRPC authors\)\|DO NOT EDIT" 2>&1 | tee /dev/stderr | (! read) -git ls-files "*.go" | xargs grep -l '"unsafe"' 2>&1 | (! grep -v '_test.go') | tee /dev/stderr | (! read) -git ls-files "*.go" | xargs grep -l '"math/rand"' 2>&1 | (! grep -v '^examples\|^stress\|grpcrand') | tee /dev/stderr | (! read) -gofmt -s -d -l . 2>&1 | tee /dev/stderr | (! read) -goimports -l . 2>&1 | tee /dev/stderr | (! read) -golint ./... 2>&1 | (grep -vE "(_mock|\.pb)\.go:" || true) | tee /dev/stderr | (! read) +# - Do not import math/rand for real library code. Use internal/grpcrand for +# thread safety. +git ls-files "*.go" | xargs grep -l '"math/rand"' 2>&1 | (! grep -v '^examples\|^stress\|grpcrand') -# Undo any edits made by this script. -cleanup() { - git reset --hard HEAD -} -trap cleanup EXIT +# - Ensure all ptypes proto packages are renamed when importing. +git ls-files "*.go" | (! xargs grep "\(import \|^\s*\)\"github.com/golang/protobuf/ptypes/") -# Rewrite golang.org/x/net/context -> context imports (see grpc/grpc-go#1484). -# TODO: Remove this mangling once "context" is imported directly (grpc/grpc-go#711). -git ls-files "*.go" | xargs sed -i 's:"golang.org/x/net/context":"context":' -set +o pipefail -# TODO: Stop filtering pb.go files once golang/protobuf#214 is fixed. -go tool vet -all . 2>&1 | grep -vE '(clientconn|transport\/transport_test).go:.*cancel (function|var)' | grep -vF '.pb.go:' | tee /dev/stderr | (! read) -set -o pipefail -git reset --hard HEAD - -if [[ "$check_proto" = "true" ]]; then - PATH="/home/travis/bin:$PATH" make proto && \ - git status --porcelain 2>&1 | (! read) || \ +# - Check imports that are illegal in appengine (until Go 1.11). +# TODO: Remove when we drop Go 1.10 support +go list -f {{.Dir}} ./... | xargs go run test/go_vet/vet.go + +# - gofmt, goimports, golint (with exceptions for generated code), go vet. +gofmt -s -d -l . 2>&1 | fail_on_output +goimports -l . 2>&1 | fail_on_output +golint ./... 2>&1 | (! grep -vE "(_mock|\.pb)\.go:") +go tool vet -all . + +# - Check that generated proto files are up to date. +if [[ -z "${VET_SKIP_PROTO}" ]]; then + PATH="/home/travis/bin:${PATH}" make proto && \ + git status --porcelain 2>&1 | fail_on_output || \ + (git status; git --no-pager diff; exit 1) +fi + +# - Check that our module is tidy. +if go help mod >& /dev/null; then + go mod tidy && \ + git status --porcelain 2>&1 | fail_on_output || \ (git status; git --no-pager diff; exit 1) fi +# - Collection of static analysis checks +### HACK HACK HACK: Remove once staticcheck works with modules. +# Make a symlink in ${GOPATH}/src to its ${GOPATH}/pkg/mod equivalent for every package we use. +for x in $(find "${GOPATH}/pkg/mod" -name '*@*' | grep -v \/mod\/cache\/); do + pkg="$(echo ${x#"${GOPATH}/pkg/mod/"} | cut -f1 -d@)"; + # If multiple versions exist, just use the existing one. + if [[ -L "${GOPATH}/src/${pkg}" ]]; then continue; fi + mkdir -p "$(dirname "${GOPATH}/src/${pkg}")"; + ln -s $x "${GOPATH}/src/${pkg}"; +done +### END HACK HACK HACK + # TODO(menghanl): fix errors in transport_test. staticcheck -ignore ' -google.golang.org/grpc/transport/transport_test.go:SA2002 -google.golang.org/grpc/benchmark/benchmain/main.go:SA1019 -google.golang.org/grpc/stats/stats_test.go:SA1019 -google.golang.org/grpc/test/end2end_test.go:SA1019 -google.golang.org/grpc/balancer_test.go:SA1019 -google.golang.org/grpc/balancer.go:SA1019 -google.golang.org/grpc/clientconn_test.go:SA1019 +balancer.go:SA1019 +balancer_test.go:SA1019 +clientconn_test.go:SA1019 +balancer/roundrobin/roundrobin_test.go:SA1019 +benchmark/benchmain/main.go:SA1019 +internal/transport/handler_server.go:SA1019 +internal/transport/handler_server_test.go:SA1019 +internal/transport/transport_test.go:SA2002 +stats/stats_test.go:SA1019 +test/channelz_test.go:SA1019 +test/end2end_test.go:SA1019 ' ./... misspell -error .