Fresh dep ensure

This commit is contained in:
Mike Cronce
2018-11-26 13:23:56 -05:00
parent 93cb8a04d7
commit 407478ab9a
9016 changed files with 551394 additions and 279685 deletions

2
vendor/google.golang.org/grpc/.github/lock.yml generated vendored Normal file
View File

@ -0,0 +1,2 @@
daysUntilLock: 180
lockComment: false

View File

@ -1,24 +1,39 @@
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: 1.8.x
- go: 1.6.x
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

View File

@ -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

15
vendor/google.golang.org/grpc/Documentation/proxy.md generated vendored Normal file
View File

@ -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).

View File

@ -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)
```

View File

@ -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

View File

@ -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.

View File

@ -19,7 +19,6 @@
package grpc
import (
"fmt"
"net"
"sync"
@ -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}}
}

View File

@ -28,6 +28,7 @@ import (
"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,12 @@ 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
}
// ClientConn represents a gRPC ClientConn.
//
@ -125,6 +131,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 +151,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.

View File

@ -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,
}

View File

@ -25,7 +25,7 @@
package grpclb
import (
"fmt"
"errors"
"strconv"
"strings"
"sync"
@ -37,7 +37,9 @@ import (
"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()
}

View File

@ -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)
}

View File

@ -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

View File

@ -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
}
@ -257,6 +257,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 +273,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

View File

@ -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

View File

@ -66,6 +66,7 @@ import (
"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)

View File

@ -28,12 +28,12 @@ import (
"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()
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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

View File

@ -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()
}

View File

@ -23,7 +23,6 @@ import (
"math"
"runtime"
"sync"
"syscall"
"time"
"golang.org/x/net/context"
@ -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))

View File

@ -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()

View File

@ -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
}

View File

@ -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:
// /<service>/<method>
// 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
// <host> or <host>:<port> .
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,
}

View File

@ -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)
}

View File

@ -32,8 +32,8 @@ import (
"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 (

View File

@ -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
@ -1249,15 +1251,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 {
@ -1560,11 +1566,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 {
@ -1707,12 +1715,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 {

View File

@ -0,0 +1,105 @@
// +build !appengine,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 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
}

View File

@ -1,3 +1,5 @@
// +build !linux appengine !go1.7
/*
*
* Copyright 2018 gRPC authors.
@ -16,12 +18,13 @@
*
*/
//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 (
channelzpb "google.golang.org/grpc/channelz/grpc_channelz_v1"
"google.golang.org/grpc/internal/channelz"
)
func init() {
panic("Don't import this package. For grpclb, see package google.golang.org/grpc/balancer/grpclb")
func sockoptToProto(skopts *channelz.SocketOptionData) []*channelzpb.SocketOption {
return nil
}

View File

@ -23,20 +23,31 @@ package service
import (
"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/connectivity"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/internal/channelz"
)
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 +73,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 +133,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 +168,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 +239,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)
}

View File

@ -0,0 +1,152 @@
// +build linux,!appengine,go1.7
// +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 (
"reflect"
"strconv"
"testing"
"github.com/golang/protobuf/ptypes"
durpb "github.com/golang/protobuf/ptypes/duration"
"golang.org/x/net/context"
"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))
}
}
}

View File

@ -19,16 +19,19 @@
package service
import (
"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,6 +39,13 @@ 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.
@ -92,11 +102,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 +123,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 +174,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 +209,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 +225,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 +263,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{
{
@ -359,40 +404,131 @@ func TestGetServerSockets(t *testing.T) {
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 +537,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 +624,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))

View File

@ -0,0 +1,33 @@
// +build 386,linux,!appengine,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 service
import (
"golang.org/x/sys/unix"
channelzpb "google.golang.org/grpc/channelz/grpc_channelz_v1"
)
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
}

View File

@ -0,0 +1,32 @@
// +build amd64,linux,!appengine,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 service
import (
"golang.org/x/sys/unix"
channelzpb "google.golang.org/grpc/channelz/grpc_channelz_v1"
)
func protoToTime(protoTime *channelzpb.SocketOptionTimeout) *unix.Timeval {
timeout := &unix.Timeval{}
timeout.Sec, timeout.Usec = convertToDuration(protoTime.GetDuration())
return timeout
}

File diff suppressed because it is too large Load Diff

View File

@ -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 (
"net"
"sync"
"sync/atomic"
"testing"
"time"
"golang.org/x/net/context"
"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) {
}
}

View File

@ -19,6 +19,8 @@
package grpc
import (
"errors"
"fmt"
"math"
"net"
"sync/atomic"
@ -31,6 +33,7 @@ import (
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/internal/backoff"
"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"
@ -131,11 +134,11 @@ func TestDialWithMultipleBackendsNotSendingServerPreface(t *testing.T) {
func TestDialWaitsForServerSettings(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{})
sent := make(chan struct{})
dialDone := make(chan struct{})
@ -143,7 +146,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
@ -162,10 +165,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(), WithWaitForHandshake(), WithBlock())
close(dialDone)
if err != nil {
cancel()
t.Fatalf("Error while dialing. Err: %v", err)
}
defer client.Close()
@ -178,12 +180,53 @@ func TestDialWaitsForServerSettings(t *testing.T) {
}
func TestDialWaitsForServerSettingsAndFails(t *testing.T) {
defer leakcheck.Check(t)
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 / 2 }
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
client, err := DialContext(ctx, lis.Addr().String(), WithInsecure(), WithWaitForHandshake(), WithBlock())
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) {
// 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()
// Call this only after transportMonitor goroutine has ended.
defer func() {
atomic.StoreInt64((*int64)(&mutableMinConnectTimeout), int64(mctBkp))
}()
defer leakcheck.Check(t)
atomic.StoreInt64((*int64)(&mutableMinConnectTimeout), int64(time.Millisecond)*500)
@ -204,6 +247,7 @@ func TestCloseConnectionWhenServerPrefaceNotReceived(t *testing.T) {
}
}()
done := make(chan struct{})
accepted := make(chan struct{})
go func() { // Launch the server.
defer close(done)
conn1, err := lis.Accept()
@ -218,6 +262,7 @@ func TestCloseConnectionWhenServerPrefaceNotReceived(t *testing.T) {
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)
@ -242,26 +287,33 @@ func TestCloseConnectionWhenServerPrefaceNotReceived(t *testing.T) {
if err != nil {
t.Fatalf("Error while dialing. Err: %v", err)
}
time.Sleep(time.Second * 2) // Let things play out.
// 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 * 2)
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 +323,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 +339,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 +482,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 +674,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()
@ -676,3 +764,73 @@ func TestDisableServiceConfigOption(t *testing.T) {
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 _, <nil>", 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.
}

View File

@ -32,10 +32,10 @@ import (
"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,

View File

@ -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) {

View File

@ -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)

View File

@ -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 (

View File

@ -18,9 +18,8 @@
//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 (
"net"

View File

@ -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
}

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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
}
}

View File

@ -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()

View File

@ -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.

View File

@ -28,7 +28,7 @@ import (
"reflect"
"testing"
"google.golang.org/grpc/credentials/alts/core"
core "google.golang.org/grpc/credentials/alts/internal"
)
var (

View File

@ -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
}

View File

@ -30,11 +30,11 @@ import (
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 (

View File

@ -25,9 +25,9 @@ import (
"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

View File

@ -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)
proto.RegisterFile("grpc/gcp/altscontext.proto", fileDescriptor_altscontext_f6b7868f9a30497f)
}
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,
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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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.

View File

@ -29,7 +29,6 @@ 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
}

View File

@ -24,7 +24,7 @@ import (
"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 "" }

View File

@ -31,6 +31,7 @@ import (
"net"
"strings"
"github.com/golang/protobuf/proto"
"golang.org/x/net/context"
)
@ -107,6 +108,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 +138,18 @@ func (t TLSInfo) AuthType() string {
return "tls"
}
// GetChannelzSecurityValue returns security info requested by channelz.
func (t TLSInfo) GetChannelzSecurityValue() 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 +187,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 tlsConn{Conn: conn, rawConn: rawConn}, TLSInfo{conn.ConnectionState()}, nil
}
func (c *tlsCreds) ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error) {
@ -163,7 +195,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 tlsConn{Conn: conn, rawConn: rawConn}, TLSInfo{conn.ConnectionState()}, nil
}
func (c *tlsCreds) Clone() TransportCredentials {
@ -218,3 +250,63 @@ 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() {}
type tlsConn struct {
*tls.Conn
rawConn net.Conn
}
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",
}

View File

@ -1,5 +1,4 @@
// +build go1.7
// +build !go1.8
// +build go1.7,!go1.8
/*
*

View File

@ -24,6 +24,14 @@ import (
"crypto/tls"
)
func init() {
cipherSuiteLookup[tls.TLS_RSA_WITH_AES_128_CBC_SHA256] = "TLS_RSA_WITH_AES_128_CBC_SHA256"
cipherSuiteLookup[tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256] = "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"
cipherSuiteLookup[tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256] = "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"
cipherSuiteLookup[tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305] = "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"
cipherSuiteLookup[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.

35
vendor/google.golang.org/grpc/credentials/go19.go generated vendored Normal file
View File

@ -0,0 +1,35 @@
// +build go1.9,!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 credentials
import (
"errors"
"syscall"
)
// implements the syscall.Conn interface
func (c tlsConn) SyscallConn() (syscall.RawConn, error) {
conn, ok := c.rawConn.(syscall.Conn)
if !ok {
return nil, errors.New("RawConn does not implement syscall.Conn")
}
return conn.SyscallConn()
}

View File

@ -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 (
"fmt"
"time"
"golang.org/x/net/context"
"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
}

465
vendor/google.golang.org/grpc/dialoptions.go generated vendored Normal file
View File

@ -0,0 +1,465 @@
/*
*
* 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"
"net"
"time"
"golang.org/x/net/context"
"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
waitForHandshake bool
channelzParentID int64
disableServiceConfig bool
disableRetry 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. Experimental API.
func WithWaitForHandshake() DialOption {
return newFuncDialOption(func(o *dialOptions) {
o.waitForHandshake = true
})
}
// 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
})
}
func defaultDialOptions() dialOptions {
return dialOptions{
disableRetry: !envconfig.Retry,
copts: transport.ConnectOptions{
WriteBufferSize: defaultWriteBufSize,
ReadBufferSize: defaultReadBufSize,
},
}
}

21
vendor/google.golang.org/grpc/go.mod generated vendored Normal file
View File

@ -0,0 +1,21 @@
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/lint v0.0.0-20180702182130-06c8688daad7
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-20180702182130-06c8688daad7 // indirect
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
)

34
vendor/google.golang.org/grpc/go.sum generated vendored Normal file
View File

@ -0,0 +1,34 @@
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/lint v0.0.0-20180702182130-06c8688daad7 h1:2hRPrmiwPrp3fQX967rNJIhQPtiGXdlQWAxKbKw3VHA=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
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-20180702182130-06c8688daad7 h1:00BeQWmeaGazuOrq8Q5K5d3/cHaGuFrZzpaHBXfrsUA=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/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=

View File

@ -28,8 +28,8 @@ import (
"golang.org/x/net/context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/internal/transport"
"google.golang.org/grpc/status"
"google.golang.org/grpc/transport"
)
// dialContext connects to the address on the named network.
@ -50,12 +50,13 @@ 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.StreamError:
return status.Error(e.Code, e.Desc)
case transport.ConnectionError:
return status.Error(codes.Unavailable, e.Desc)
default:

View File

@ -29,8 +29,8 @@ import (
netctx "golang.org/x/net/context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/internal/transport"
"google.golang.org/grpc/status"
"google.golang.org/grpc/transport"
)
// dialContext connects to the address on the named network.
@ -51,12 +51,13 @@ 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.StreamError:
return status.Error(e.Code, e.Desc)
case transport.ConnectionError:
return status.Error(codes.Unavailable, e.Desc)
default:

View File

@ -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,
}

View File

@ -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;
}

View File

@ -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,
}

View File

@ -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);
}

View File

@ -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,
}

View File

@ -36,12 +36,14 @@ 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[healthpb.Health_WatchServer]chan healthpb.HealthCheckResponse_ServingStatus
}
// NewServer returns a new Server.
func NewServer() *Server {
return &Server{
statusMap: make(map[string]healthpb.HealthCheckResponse_ServingStatus),
statusMap: map[string]healthpb.HealthCheckResponse_ServingStatus{"": healthpb.HealthCheckResponse_SERVING},
updates: make(map[string]map[healthpb.Health_WatchServer]chan healthpb.HealthCheckResponse_ServingStatus),
}
}
@ -49,24 +51,67 @@ func NewServer() *Server {
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.
if servingStatus, ok := s.statusMap[in.Service]; ok {
return &healthpb.HealthCheckResponse{
Status: healthpb.HealthCheckResponse_SERVING,
}, nil
}
if status, ok := s.statusMap[in.Service]; ok {
return &healthpb.HealthCheckResponse{
Status: status,
Status: servingStatus,
}, nil
}
return nil, status.Error(codes.NotFound, "unknown service")
}
// Watch implements `service Health`.
func (s *Server) Watch(in *healthpb.HealthCheckRequest, stream healthpb.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[healthpb.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()
for {
select {
// Status updated. Sends the up-to-date status to the client.
case servingStatus := <-update:
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, status healthpb.HealthCheckResponse_ServingStatus) {
func (s *Server) SetServingStatus(service string, servingStatus healthpb.HealthCheckResponse_ServingStatus) {
s.mu.Lock()
s.statusMap[service] = status
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
}
s.mu.Unlock()
}

33
vendor/google.golang.org/grpc/health/health_test.go generated vendored Normal file
View File

@ -0,0 +1,33 @@
/*
*
* 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"
pb "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()
pb.RegisterHealthServer(s, health.NewServer())
s.Stop()
}

6
vendor/google.golang.org/grpc/install_gae.sh generated vendored Executable file
View File

@ -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"

View File

@ -0,0 +1,141 @@
/*
*
* 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 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 Logger *logger
func init() {
const envStr = "GRPC_BINARY_LOG_FILTER"
configStr := os.Getenv(envStr)
Logger = 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)
}

View File

@ -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)
}
}
}

View File

@ -0,0 +1,206 @@
/*
*
* 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.
//
// 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 {
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)
}

View File

@ -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)
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)
}
}
}

View File

@ -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 should only be a proto.Message. Could add support for other
// message types in the future.
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 should only be a proto.Message. Could add support for other
// message types in the future.
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", "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
}

View File

@ -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(), 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)
}
}
}

View File

@ -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/

View File

@ -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)
}
}
}

View File

@ -0,0 +1,64 @@
/*
*
* 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 (
"io"
"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) {
defaultSink = s
}
// Sink writes log entry into the binary log sink.
type Sink interface {
Write(*pb.GrpcLogEntry)
}
type noopSink struct{}
func (ns *noopSink) Write(*pb.GrpcLogEntry) {}
// NewWriterSink creates a binary log sink with the given writer.
func NewWriterSink(w io.Writer) Sink {
return &writerSink{out: w}
}
type writerSink struct {
out io.Writer
}
func (fs *writerSink) Write(e *pb.GrpcLogEntry) {
b, err := proto.Marshal(e)
if err != nil {
grpclog.Infof("binary logging: failed to marshal proto message: %v", err)
}
fs.out.Write(b)
}

View File

@ -0,0 +1,41 @@
/*
*
* 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"
"strings"
)
// 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 /")
}
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
}

View File

@ -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)
}
}
}

View File

@ -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,7 +557,7 @@ func (c *channelMap) GetServerSockets(id int64, startID int64) ([]*SocketMetric,
for k := range svrskts {
ids = append(ids, k)
}
sort.Sort((int64Slice(ids)))
sort.Sort(int64Slice(ids))
idx := sort.Search(len(ids), func(i int) bool { return ids[i] >= id })
count := 0
var end bool
@ -518,6 +605,7 @@ func (c *channelMap) GetChannel(id int64) *ChannelMetric {
cm.ChannelData = cn.c.ChannelzMetric()
cm.ID = cn.id
cm.RefName = cn.refName
cm.Trace = cn.trace.dumpData()
return cm
}
@ -536,6 +624,7 @@ func (c *channelMap) GetSubChannel(id int64) *SubChannelMetric {
cm.ChannelData = sc.c.ChannelzMetric()
cm.ID = sc.id
cm.RefName = sc.refName
cm.Trace = sc.trace.dumpData()
return cm
}

View File

@ -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
}

View File

@ -0,0 +1,53 @@
// +build !appengine,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 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
}
}

View File

@ -0,0 +1,44 @@
// +build !linux appengine !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 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.")
})
}

Some files were not shown because too many files have changed in this diff Show More