diff --git a/interop/grpc_testing/test.pb.go b/interop/grpc_testing/test.pb.go index 1c8e33bc95a3..9b44623c25ae 100644 --- a/interop/grpc_testing/test.pb.go +++ b/interop/grpc_testing/test.pb.go @@ -712,10 +712,12 @@ type LoadBalancerStatsResponse struct { // The number of completed RPCs for each peer. RpcsByPeer map[string]int32 `protobuf:"bytes,1,rep,name=rpcs_by_peer,json=rpcsByPeer,proto3" json:"rpcs_by_peer,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` // The number of RPCs that failed to record a remote peer. - NumFailures int32 `protobuf:"varint,2,opt,name=num_failures,json=numFailures,proto3" json:"num_failures,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + NumFailures int32 `protobuf:"varint,2,opt,name=num_failures,json=numFailures,proto3" json:"num_failures,omitempty"` + // The number of completed RPCs for each method (UnaryCall or EmptyCall). + RpcsByMethod map[string]*LoadBalancerStatsResponse_RpcsByPeer `protobuf:"bytes,3,rep,name=rpcs_by_method,json=rpcsByMethod,proto3" json:"rpcs_by_method,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 *LoadBalancerStatsResponse) Reset() { *m = LoadBalancerStatsResponse{} } @@ -757,6 +759,53 @@ func (m *LoadBalancerStatsResponse) GetNumFailures() int32 { return 0 } +func (m *LoadBalancerStatsResponse) GetRpcsByMethod() map[string]*LoadBalancerStatsResponse_RpcsByPeer { + if m != nil { + return m.RpcsByMethod + } + return nil +} + +type LoadBalancerStatsResponse_RpcsByPeer struct { + // The number of completed RPCs for each peer. + RpcsByPeer map[string]int32 `protobuf:"bytes,1,rep,name=rpcs_by_peer,json=rpcsByPeer,proto3" json:"rpcs_by_peer,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LoadBalancerStatsResponse_RpcsByPeer) Reset() { *m = LoadBalancerStatsResponse_RpcsByPeer{} } +func (m *LoadBalancerStatsResponse_RpcsByPeer) String() string { return proto.CompactTextString(m) } +func (*LoadBalancerStatsResponse_RpcsByPeer) ProtoMessage() {} +func (*LoadBalancerStatsResponse_RpcsByPeer) Descriptor() ([]byte, []int) { + return fileDescriptor_534063719f48d90d, []int{11, 0} +} + +func (m *LoadBalancerStatsResponse_RpcsByPeer) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_LoadBalancerStatsResponse_RpcsByPeer.Unmarshal(m, b) +} +func (m *LoadBalancerStatsResponse_RpcsByPeer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_LoadBalancerStatsResponse_RpcsByPeer.Marshal(b, m, deterministic) +} +func (m *LoadBalancerStatsResponse_RpcsByPeer) XXX_Merge(src proto.Message) { + xxx_messageInfo_LoadBalancerStatsResponse_RpcsByPeer.Merge(m, src) +} +func (m *LoadBalancerStatsResponse_RpcsByPeer) XXX_Size() int { + return xxx_messageInfo_LoadBalancerStatsResponse_RpcsByPeer.Size(m) +} +func (m *LoadBalancerStatsResponse_RpcsByPeer) XXX_DiscardUnknown() { + xxx_messageInfo_LoadBalancerStatsResponse_RpcsByPeer.DiscardUnknown(m) +} + +var xxx_messageInfo_LoadBalancerStatsResponse_RpcsByPeer proto.InternalMessageInfo + +func (m *LoadBalancerStatsResponse_RpcsByPeer) GetRpcsByPeer() map[string]int32 { + if m != nil { + return m.RpcsByPeer + } + return nil +} + func init() { proto.RegisterEnum("grpc.testing.PayloadType", PayloadType_name, PayloadType_value) proto.RegisterEnum("grpc.testing.GrpclbRouteType", GrpclbRouteType_name, GrpclbRouteType_value) @@ -772,75 +821,82 @@ func init() { proto.RegisterType((*StreamingOutputCallResponse)(nil), "grpc.testing.StreamingOutputCallResponse") proto.RegisterType((*LoadBalancerStatsRequest)(nil), "grpc.testing.LoadBalancerStatsRequest") proto.RegisterType((*LoadBalancerStatsResponse)(nil), "grpc.testing.LoadBalancerStatsResponse") + proto.RegisterMapType((map[string]*LoadBalancerStatsResponse_RpcsByPeer)(nil), "grpc.testing.LoadBalancerStatsResponse.RpcsByMethodEntry") proto.RegisterMapType((map[string]int32)(nil), "grpc.testing.LoadBalancerStatsResponse.RpcsByPeerEntry") + proto.RegisterType((*LoadBalancerStatsResponse_RpcsByPeer)(nil), "grpc.testing.LoadBalancerStatsResponse.RpcsByPeer") + proto.RegisterMapType((map[string]int32)(nil), "grpc.testing.LoadBalancerStatsResponse.RpcsByPeer.RpcsByPeerEntry") } func init() { proto.RegisterFile("interop/grpc_testing/test.proto", fileDescriptor_534063719f48d90d) } var fileDescriptor_534063719f48d90d = []byte{ - // 1019 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0xfd, 0x6e, 0x1b, 0x45, - 0x10, 0xcf, 0x39, 0x71, 0x1c, 0x8f, 0x5d, 0xc7, 0xdd, 0xb4, 0x70, 0x71, 0x28, 0x35, 0x07, 0xa2, - 0xa6, 0xa8, 0x0e, 0x72, 0xc5, 0x87, 0x2a, 0x15, 0x14, 0x27, 0x4e, 0x88, 0xea, 0xda, 0xe6, 0x1c, - 0x83, 0xca, 0x3f, 0xa7, 0xcd, 0x79, 0x72, 0x39, 0x71, 0x5f, 0xec, 0xed, 0x45, 0xb8, 0xff, 0x20, - 0xf1, 0x08, 0xbc, 0x02, 0x8f, 0xc1, 0x8b, 0xf0, 0x38, 0x68, 0xf7, 0xee, 0xfc, 0x79, 0x51, 0x13, - 0x2a, 0xfa, 0x97, 0x77, 0xe7, 0xe3, 0x37, 0x33, 0xbf, 0x99, 0x1d, 0x1f, 0x3c, 0xb4, 0x3d, 0x8e, - 0xcc, 0x0f, 0xf6, 0x2d, 0x16, 0x98, 0x06, 0xc7, 0x90, 0xdb, 0x9e, 0xb5, 0x2f, 0x7e, 0x9b, 0x01, - 0xf3, 0xb9, 0x4f, 0xca, 0x42, 0xd1, 0x4c, 0x14, 0x5a, 0x01, 0xf2, 0x1d, 0x37, 0xe0, 0x13, 0xad, - 0x0b, 0x85, 0x01, 0x9d, 0x38, 0x3e, 0x1d, 0x93, 0x27, 0xb0, 0xc1, 0x27, 0x01, 0xaa, 0x4a, 0x5d, - 0x69, 0x54, 0x5a, 0xbb, 0xcd, 0x79, 0x87, 0x66, 0x62, 0x74, 0x36, 0x09, 0x50, 0x97, 0x66, 0x84, - 0xc0, 0xc6, 0xb9, 0x3f, 0x9e, 0xa8, 0xb9, 0xba, 0xd2, 0x28, 0xeb, 0xf2, 0xac, 0x3d, 0x03, 0xe8, - 0x98, 0x97, 0xfe, 0x90, 0x53, 0x1e, 0x85, 0xc2, 0xc2, 0xf4, 0xc7, 0x31, 0x60, 0x5e, 0x97, 0x67, - 0xa2, 0x42, 0xc1, 0xc5, 0x30, 0xa4, 0x16, 0x4a, 0xc7, 0xa2, 0x9e, 0x5e, 0xb5, 0x3f, 0xd7, 0xe1, - 0xce, 0xd0, 0x76, 0x03, 0x07, 0x75, 0xfc, 0x35, 0xc2, 0x90, 0x93, 0x6f, 0xe1, 0x0e, 0xc3, 0x30, - 0xf0, 0xbd, 0x10, 0x8d, 0x9b, 0x65, 0x56, 0x4e, 0xed, 0xc5, 0x8d, 0x7c, 0x3c, 0xe7, 0x1f, 0xda, - 0xaf, 0xe3, 0x88, 0xf9, 0x99, 0xd1, 0xd0, 0x7e, 0x8d, 0x64, 0x1f, 0x0a, 0x41, 0x8c, 0xa0, 0xae, - 0xd7, 0x95, 0x46, 0xa9, 0x75, 0x3f, 0x13, 0x5e, 0x4f, 0xad, 0x04, 0xea, 0x85, 0xed, 0x38, 0x46, - 0x14, 0x22, 0xf3, 0xa8, 0x8b, 0xea, 0x46, 0x5d, 0x69, 0x6c, 0xe9, 0x65, 0x21, 0x1c, 0x25, 0x32, - 0xd2, 0x80, 0xaa, 0x34, 0xf2, 0x69, 0xc4, 0x2f, 0x8d, 0xd0, 0xf4, 0x03, 0x54, 0xf3, 0xd2, 0xae, - 0x22, 0xe4, 0x7d, 0x21, 0x1e, 0x0a, 0x29, 0x39, 0x80, 0xed, 0x59, 0x92, 0x92, 0x37, 0xb5, 0x20, - 0xf3, 0x50, 0x17, 0xf3, 0x98, 0xf1, 0xaa, 0x57, 0xa6, 0x05, 0xc4, 0x3c, 0x7f, 0x02, 0x12, 0xd4, - 0x08, 0x91, 0x5d, 0x21, 0x33, 0xec, 0xb1, 0x5a, 0x9c, 0xa5, 0x34, 0x94, 0xc2, 0xd3, 0x31, 0x79, - 0x0a, 0xef, 0x49, 0x2b, 0x81, 0xea, 0x9c, 0x1b, 0xcc, 0x8f, 0x78, 0x42, 0x2b, 0x48, 0xeb, 0x1d, - 0xa1, 0x3d, 0x91, 0x4a, 0x5d, 0xe8, 0x04, 0x85, 0xda, 0x1f, 0x39, 0xa8, 0xa4, 0x4d, 0x89, 0x63, - 0xce, 0x13, 0xa6, 0xdc, 0x88, 0xb0, 0x1a, 0x6c, 0x4d, 0xb9, 0x8a, 0x7b, 0x3e, 0xbd, 0x93, 0x87, - 0x50, 0x9a, 0xa7, 0x68, 0x5d, 0xaa, 0xc1, 0x9f, 0xd1, 0xb3, 0x07, 0xc5, 0x59, 0x59, 0x1b, 0xb1, - 0x77, 0x98, 0x96, 0x74, 0x0a, 0x77, 0x57, 0xab, 0xc9, 0xcb, 0x21, 0x79, 0xb0, 0x98, 0xd4, 0x52, - 0x5d, 0xfa, 0xb6, 0xb5, 0x28, 0x10, 0x49, 0x5e, 0xfa, 0x21, 0x97, 0x49, 0x6e, 0xc6, 0x61, 0xd2, - 0xbb, 0xd6, 0x85, 0xdd, 0x21, 0x67, 0x48, 0x5d, 0xdb, 0xb3, 0x4e, 0xbd, 0x20, 0xe2, 0x87, 0xd4, - 0x71, 0xd2, 0x21, 0xbd, 0x2d, 0x1d, 0xda, 0x19, 0xd4, 0xb2, 0xd0, 0x12, 0x76, 0xbf, 0x82, 0xf7, - 0xa9, 0x65, 0x31, 0xb4, 0x28, 0xc7, 0xb1, 0x91, 0xf8, 0xc4, 0xd3, 0x1b, 0x3f, 0xa3, 0xfb, 0x33, - 0x75, 0x02, 0x2d, 0xc6, 0x58, 0x3b, 0x05, 0x92, 0x62, 0x0c, 0x28, 0xa3, 0x2e, 0x72, 0x64, 0xf2, - 0x05, 0xce, 0xb9, 0xca, 0xb3, 0xa0, 0x5c, 0xee, 0x8a, 0x2b, 0x2a, 0x66, 0x38, 0x79, 0x13, 0x90, - 0x8a, 0x46, 0xa1, 0xf6, 0x57, 0x6e, 0x2e, 0xc3, 0x7e, 0xc4, 0x97, 0x0a, 0x7e, 0xdb, 0x57, 0xf9, - 0x03, 0xec, 0x4c, 0xfd, 0x83, 0x69, 0xaa, 0x6a, 0xae, 0xbe, 0xde, 0x28, 0xb5, 0xea, 0x8b, 0x28, - 0xab, 0x25, 0xe9, 0x84, 0xad, 0x96, 0x79, 0xeb, 0x37, 0xfc, 0xf6, 0x8f, 0x4e, 0xeb, 0xc1, 0x5e, - 0x26, 0x49, 0xff, 0xf1, 0x95, 0x68, 0x3f, 0x82, 0xda, 0xf5, 0xe9, 0xb8, 0x4d, 0x1d, 0xea, 0x99, - 0xc8, 0x44, 0x94, 0x30, 0xa5, 0x7c, 0x17, 0xb6, 0xbc, 0xc8, 0x35, 0x58, 0x60, 0x86, 0x49, 0x2b, - 0x0b, 0x5e, 0xe4, 0xea, 0x81, 0x19, 0x8a, 0x6e, 0x72, 0xdb, 0x45, 0x3f, 0xe2, 0x46, 0x88, 0x66, - 0xda, 0xcd, 0x44, 0x34, 0x44, 0x53, 0xfb, 0x47, 0x81, 0xdd, 0x0c, 0xe0, 0x24, 0xcd, 0x57, 0x50, - 0x16, 0xa8, 0xc6, 0xf9, 0xc4, 0x08, 0x10, 0x99, 0xaa, 0xc8, 0x2e, 0x7c, 0xbd, 0x98, 0xeb, 0xb5, - 0xee, 0x4d, 0x91, 0x42, 0x7b, 0x32, 0x40, 0x64, 0x1d, 0x8f, 0xb3, 0x89, 0x0e, 0x6c, 0x2a, 0x20, - 0x1f, 0x41, 0x59, 0x24, 0x7d, 0x41, 0x6d, 0x27, 0x62, 0x98, 0x0e, 0x5a, 0xc9, 0x8b, 0xdc, 0xe3, - 0x44, 0x54, 0x7b, 0x0e, 0xdb, 0x4b, 0x08, 0xa4, 0x0a, 0xeb, 0xbf, 0xe0, 0x44, 0x56, 0x59, 0xd4, - 0xc5, 0x91, 0xdc, 0x83, 0xfc, 0x15, 0x75, 0xa2, 0x74, 0x7b, 0xc7, 0x97, 0x67, 0xb9, 0x6f, 0x94, - 0xc7, 0xdf, 0x41, 0x69, 0x6e, 0xcc, 0x48, 0x15, 0xca, 0x87, 0xfd, 0x97, 0x03, 0xbd, 0x33, 0x1c, - 0x1e, 0xb4, 0xbb, 0x9d, 0xea, 0x1a, 0x21, 0x50, 0x19, 0xf5, 0x16, 0x64, 0x0a, 0x01, 0xd8, 0xd4, - 0x0f, 0x7a, 0x47, 0xfd, 0x97, 0xd5, 0xdc, 0x63, 0x1f, 0xb6, 0x97, 0x16, 0x03, 0x79, 0x00, 0xbb, - 0x27, 0xfa, 0xe0, 0xb0, 0xdb, 0x36, 0xf4, 0xfe, 0xe8, 0xac, 0x63, 0x9c, 0xbd, 0x1a, 0x74, 0x8c, - 0x51, 0xef, 0x45, 0xaf, 0xff, 0x53, 0xaf, 0xba, 0x46, 0x3e, 0x84, 0xda, 0xaa, 0xfa, 0xf8, 0xa0, - 0xdb, 0x6d, 0x1f, 0x1c, 0xbe, 0xa8, 0x2a, 0xd9, 0xee, 0x42, 0xd7, 0xe9, 0x1d, 0x55, 0x73, 0xad, - 0xbf, 0x37, 0xa0, 0x74, 0x86, 0x21, 0x17, 0x4b, 0xd9, 0x36, 0x91, 0x7c, 0x09, 0x45, 0xf9, 0x37, - 0x2c, 0x46, 0x87, 0xec, 0x2c, 0xcd, 0x9e, 0x50, 0xd4, 0xb2, 0x84, 0xe4, 0x18, 0x8a, 0x23, 0x8f, - 0xb2, 0xd8, 0x6d, 0x6f, 0xd1, 0x62, 0xe1, 0x2f, 0xb4, 0xf6, 0x41, 0xb6, 0x32, 0xe9, 0xbe, 0x03, - 0x3b, 0x19, 0x33, 0x4c, 0x1a, 0x4b, 0x4e, 0xd7, 0xee, 0x82, 0xda, 0x67, 0x37, 0xb0, 0x8c, 0x63, - 0x7d, 0xa1, 0x10, 0x1b, 0xc8, 0xea, 0xe2, 0x23, 0x8f, 0xae, 0x81, 0x58, 0x5e, 0xb4, 0xb5, 0xc6, - 0x9b, 0x0d, 0xe3, 0x50, 0x0d, 0x11, 0xaa, 0x72, 0x1c, 0x39, 0xce, 0x51, 0x14, 0x38, 0xf8, 0xdb, - 0xff, 0x56, 0x53, 0x43, 0x91, 0x55, 0x55, 0xbe, 0xa7, 0xce, 0xc5, 0x3b, 0x08, 0xd5, 0x1a, 0xc1, - 0xbd, 0x91, 0x27, 0x3b, 0xe8, 0xa2, 0xc7, 0x71, 0x9c, 0x4e, 0xd1, 0x73, 0xb8, 0xbb, 0x20, 0xbf, - 0xdd, 0x34, 0xb5, 0x7e, 0xcf, 0xd8, 0x3c, 0x29, 0xb4, 0x09, 0x95, 0x13, 0xe4, 0x87, 0x8e, 0x8d, - 0x1e, 0x97, 0x0a, 0xf2, 0xe9, 0x1b, 0x77, 0x43, 0x5c, 0xdb, 0xa3, 0x1b, 0xee, 0x10, 0x6d, 0xad, - 0xfd, 0xe4, 0xe7, 0xcf, 0x2d, 0xdf, 0xb7, 0x1c, 0x6c, 0x5a, 0xbe, 0x43, 0x3d, 0xab, 0xe9, 0x33, - 0x4b, 0x7e, 0xc7, 0xee, 0x67, 0x7d, 0xd4, 0x9e, 0x6f, 0xca, 0x0f, 0xda, 0xa7, 0xff, 0x06, 0x00, - 0x00, 0xff, 0xff, 0xaa, 0x43, 0x4c, 0xeb, 0xf3, 0x0a, 0x00, 0x00, + // 1083 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xdd, 0x72, 0xdb, 0xc4, + 0x17, 0x8f, 0x1c, 0x3b, 0x8e, 0x8f, 0x5d, 0xc7, 0xd9, 0xb4, 0xff, 0xbf, 0xe2, 0x50, 0x6a, 0x04, + 0x43, 0x4d, 0x99, 0x3a, 0x8c, 0x3b, 0x7c, 0x75, 0xa6, 0x30, 0x71, 0xe2, 0xa4, 0x99, 0x3a, 0xb6, + 0x91, 0x63, 0x98, 0x72, 0xa3, 0xd9, 0xc8, 0x1b, 0x45, 0x83, 0xa4, 0x15, 0xab, 0x55, 0x06, 0xf7, + 0x86, 0x19, 0x1e, 0x81, 0x57, 0xe0, 0x09, 0xb8, 0xe6, 0x6d, 0x78, 0x12, 0x66, 0x57, 0x92, 0x3f, + 0x15, 0x1a, 0x93, 0x81, 0x2b, 0xef, 0x9e, 0xcf, 0xdf, 0xf9, 0x9d, 0x3d, 0xbb, 0x16, 0x3c, 0xb2, + 0x3d, 0x4e, 0x18, 0xf5, 0xf7, 0x2d, 0xe6, 0x9b, 0x06, 0x27, 0x01, 0xb7, 0x3d, 0x6b, 0x5f, 0xfc, + 0x36, 0x7c, 0x46, 0x39, 0x45, 0x25, 0xa1, 0x68, 0xc4, 0x0a, 0x2d, 0x0f, 0xb9, 0xb6, 0xeb, 0xf3, + 0xb1, 0xd6, 0x81, 0x7c, 0x1f, 0x8f, 0x1d, 0x8a, 0x47, 0xe8, 0x29, 0x64, 0xf9, 0xd8, 0x27, 0xaa, + 0x52, 0x53, 0xea, 0xe5, 0xe6, 0x6e, 0x63, 0xd6, 0xa1, 0x11, 0x1b, 0x9d, 0x8f, 0x7d, 0xa2, 0x4b, + 0x33, 0x84, 0x20, 0x7b, 0x41, 0x47, 0x63, 0x35, 0x53, 0x53, 0xea, 0x25, 0x5d, 0xae, 0xb5, 0xe7, + 0x00, 0x6d, 0xf3, 0x8a, 0x0e, 0x38, 0xe6, 0x61, 0x20, 0x2c, 0x4c, 0x3a, 0x8a, 0x02, 0xe6, 0x74, + 0xb9, 0x46, 0x2a, 0xe4, 0x5d, 0x12, 0x04, 0xd8, 0x22, 0xd2, 0xb1, 0xa0, 0x27, 0x5b, 0xed, 0xd7, + 0x75, 0xb8, 0x37, 0xb0, 0x5d, 0xdf, 0x21, 0x3a, 0xf9, 0x31, 0x24, 0x01, 0x47, 0x5f, 0xc1, 0x3d, + 0x46, 0x02, 0x9f, 0x7a, 0x01, 0x31, 0x6e, 0x87, 0xac, 0x94, 0xd8, 0x8b, 0x1d, 0x7a, 0x7f, 0xc6, + 0x3f, 0xb0, 0xdf, 0x44, 0x19, 0x73, 0x53, 0xa3, 0x81, 0xfd, 0x86, 0xa0, 0x7d, 0xc8, 0xfb, 0x51, + 0x04, 0x75, 0xbd, 0xa6, 0xd4, 0x8b, 0xcd, 0x07, 0xa9, 0xe1, 0xf5, 0xc4, 0x4a, 0x44, 0xbd, 0xb4, + 0x1d, 0xc7, 0x08, 0x03, 0xc2, 0x3c, 0xec, 0x12, 0x35, 0x5b, 0x53, 0xea, 0x9b, 0x7a, 0x49, 0x08, + 0x87, 0xb1, 0x0c, 0xd5, 0xa1, 0x22, 0x8d, 0x28, 0x0e, 0xf9, 0x95, 0x11, 0x98, 0xd4, 0x27, 0x6a, + 0x4e, 0xda, 0x95, 0x85, 0xbc, 0x27, 0xc4, 0x03, 0x21, 0x45, 0x07, 0xb0, 0x35, 0x05, 0x29, 0x79, + 0x53, 0xf3, 0x12, 0x87, 0x3a, 0x8f, 0x63, 0xca, 0xab, 0x5e, 0x9e, 0x14, 0x10, 0xf1, 0xfc, 0x01, + 0xc8, 0xa0, 0x46, 0x40, 0xd8, 0x35, 0x61, 0x86, 0x3d, 0x52, 0x0b, 0x53, 0x48, 0x03, 0x29, 0x3c, + 0x1d, 0xa1, 0x67, 0xf0, 0x3f, 0x69, 0x25, 0xa2, 0x3a, 0x17, 0x06, 0xa3, 0x21, 0x8f, 0x69, 0x05, + 0x69, 0xbd, 0x23, 0xb4, 0x27, 0x52, 0xa9, 0x0b, 0x9d, 0xa0, 0x50, 0xfb, 0x25, 0x03, 0xe5, 0xa4, + 0x29, 0x51, 0xce, 0x59, 0xc2, 0x94, 0x5b, 0x11, 0x56, 0x85, 0xcd, 0x09, 0x57, 0x51, 0xcf, 0x27, + 0x7b, 0xf4, 0x08, 0x8a, 0xb3, 0x14, 0xad, 0x4b, 0x35, 0xd0, 0x29, 0x3d, 0x7b, 0x50, 0x98, 0x96, + 0x95, 0x8d, 0xbc, 0x83, 0xa4, 0xa4, 0x53, 0xd8, 0x5e, 0xae, 0x26, 0x27, 0x0f, 0xc9, 0xc3, 0x79, + 0x50, 0x0b, 0x75, 0xe9, 0x5b, 0xd6, 0xbc, 0x40, 0x80, 0xbc, 0xa2, 0x01, 0x97, 0x20, 0x37, 0xa2, + 0x34, 0xc9, 0x5e, 0xeb, 0xc0, 0xee, 0x80, 0x33, 0x82, 0x5d, 0xdb, 0xb3, 0x4e, 0x3d, 0x3f, 0xe4, + 0x87, 0xd8, 0x71, 0x92, 0x43, 0xba, 0x2a, 0x1d, 0xda, 0x39, 0x54, 0xd3, 0xa2, 0xc5, 0xec, 0x7e, + 0x06, 0xff, 0xc7, 0x96, 0xc5, 0x88, 0x85, 0x39, 0x19, 0x19, 0xb1, 0x4f, 0x74, 0x7a, 0xa3, 0x31, + 0x7a, 0x30, 0x55, 0xc7, 0xa1, 0xc5, 0x31, 0xd6, 0x4e, 0x01, 0x25, 0x31, 0xfa, 0x98, 0x61, 0x97, + 0x70, 0xc2, 0xe4, 0x04, 0xce, 0xb8, 0xca, 0xb5, 0xa0, 0x5c, 0xde, 0x15, 0xd7, 0x58, 0x9c, 0xe1, + 0x78, 0x26, 0x20, 0x11, 0x0d, 0x03, 0xed, 0xb7, 0xcc, 0x0c, 0xc2, 0x5e, 0xc8, 0x17, 0x0a, 0xbe, + 0xeb, 0x54, 0x7e, 0x03, 0x3b, 0x13, 0x7f, 0x7f, 0x02, 0x55, 0xcd, 0xd4, 0xd6, 0xeb, 0xc5, 0x66, + 0x6d, 0x3e, 0xca, 0x72, 0x49, 0x3a, 0x62, 0xcb, 0x65, 0xae, 0x3c, 0xc3, 0x77, 0x1f, 0x3a, 0xad, + 0x0b, 0x7b, 0xa9, 0x24, 0xfd, 0xc3, 0x29, 0xd1, 0xbe, 0x05, 0xb5, 0x43, 0xf1, 0xa8, 0x85, 0x1d, + 0xec, 0x99, 0x84, 0x89, 0x2c, 0x41, 0x42, 0xf9, 0x2e, 0x6c, 0x7a, 0xa1, 0x6b, 0x30, 0xdf, 0x0c, + 0xe2, 0x56, 0xe6, 0xbd, 0xd0, 0xd5, 0x7d, 0x33, 0x10, 0xdd, 0xe4, 0xb6, 0x4b, 0x68, 0xc8, 0x8d, + 0x80, 0x98, 0x49, 0x37, 0x63, 0xd1, 0x80, 0x98, 0xda, 0x9f, 0x59, 0xd8, 0x4d, 0x09, 0x1c, 0xc3, + 0x7c, 0x0d, 0x25, 0x11, 0xd5, 0xb8, 0x18, 0x1b, 0x3e, 0x21, 0x4c, 0x55, 0x64, 0x17, 0x3e, 0x9f, + 0xc7, 0x7a, 0xa3, 0x7b, 0x43, 0x40, 0x68, 0x8d, 0xfb, 0x84, 0xb0, 0xb6, 0xc7, 0xd9, 0x58, 0x07, + 0x36, 0x11, 0xa0, 0xf7, 0xa0, 0x24, 0x40, 0x5f, 0x62, 0xdb, 0x09, 0x19, 0x49, 0x0e, 0x5a, 0xd1, + 0x0b, 0xdd, 0xe3, 0x58, 0x84, 0x0c, 0x28, 0x27, 0xd9, 0x5d, 0xc2, 0xaf, 0xa8, 0x68, 0x9f, 0xc8, + 0xff, 0xe5, 0x6a, 0xf9, 0xcf, 0xa4, 0x6f, 0x84, 0xa0, 0xc4, 0x66, 0x44, 0xd5, 0xdf, 0x15, 0x80, + 0x29, 0x46, 0x34, 0x4a, 0xad, 0xb6, 0xb5, 0x7a, 0xb5, 0x7f, 0x57, 0x78, 0xf5, 0x05, 0x6c, 0x2d, + 0xa8, 0x51, 0x05, 0xd6, 0x7f, 0x20, 0x63, 0xd9, 0xbb, 0x82, 0x2e, 0x96, 0xe8, 0x3e, 0xe4, 0xae, + 0xb1, 0x13, 0x26, 0x6f, 0x52, 0xb4, 0x79, 0x9e, 0xf9, 0x42, 0xb9, 0xab, 0x7b, 0x00, 0xdb, 0x4b, + 0xac, 0xa4, 0x04, 0x78, 0x39, 0x1b, 0xa0, 0xd8, 0x6c, 0xae, 0xce, 0xc1, 0x4c, 0xd2, 0x27, 0x5f, + 0x43, 0x71, 0x66, 0xe0, 0x51, 0x05, 0x4a, 0x87, 0xbd, 0xb3, 0xbe, 0xde, 0x1e, 0x0c, 0x0e, 0x5a, + 0x9d, 0x76, 0x65, 0x0d, 0x21, 0x28, 0x0f, 0xbb, 0x73, 0x32, 0x05, 0x01, 0x6c, 0xe8, 0x07, 0xdd, + 0xa3, 0xde, 0x59, 0x25, 0xf3, 0x84, 0xc2, 0xd6, 0xc2, 0x15, 0x8d, 0x1e, 0xc2, 0xee, 0x89, 0xde, + 0x3f, 0xec, 0xb4, 0x0c, 0xbd, 0x37, 0x3c, 0x6f, 0x1b, 0xe7, 0xaf, 0xfb, 0x6d, 0x63, 0xd8, 0x7d, + 0xd5, 0xed, 0x7d, 0xd7, 0xad, 0xac, 0xa1, 0x77, 0xa1, 0xba, 0xac, 0x3e, 0x3e, 0xe8, 0x74, 0x5a, + 0x07, 0x87, 0xaf, 0x2a, 0x4a, 0xba, 0xbb, 0xd0, 0xb5, 0xbb, 0x47, 0x95, 0x4c, 0xf3, 0x8f, 0x2c, + 0x14, 0xcf, 0x49, 0xc0, 0xc5, 0xf3, 0x68, 0x9b, 0x04, 0x7d, 0x0a, 0x05, 0xf9, 0x87, 0x48, 0x0c, + 0x31, 0xda, 0x59, 0xb8, 0x05, 0x84, 0xa2, 0x9a, 0x26, 0x44, 0xc7, 0x50, 0x18, 0x7a, 0x98, 0x45, + 0x6e, 0x7b, 0xf3, 0x16, 0x73, 0x7f, 0x66, 0xaa, 0xef, 0xa4, 0x2b, 0xe3, 0x39, 0x74, 0x60, 0x27, + 0xe5, 0x36, 0x41, 0xf5, 0x05, 0xa7, 0x1b, 0x6f, 0xe5, 0xea, 0x47, 0xb7, 0xb0, 0x8c, 0x72, 0x7d, + 0xa2, 0x20, 0x1b, 0xd0, 0xf2, 0x13, 0x84, 0x1e, 0xdf, 0x10, 0x62, 0xf1, 0xc9, 0xab, 0xd6, 0xdf, + 0x6e, 0x18, 0xa5, 0xaa, 0x8b, 0x54, 0xe5, 0xe3, 0xd0, 0x71, 0x8e, 0x42, 0xdf, 0x21, 0x3f, 0xfd, + 0x6b, 0x35, 0xd5, 0x15, 0x59, 0x55, 0xf9, 0x25, 0x76, 0x2e, 0xff, 0x83, 0x54, 0xcd, 0x21, 0xdc, + 0x1f, 0x7a, 0xb2, 0x83, 0x2e, 0xf1, 0x38, 0x19, 0x25, 0xa7, 0xe8, 0x05, 0x6c, 0xcf, 0xc9, 0x57, + 0x3b, 0x4d, 0xcd, 0x9f, 0x53, 0xde, 0x80, 0x24, 0xb4, 0x09, 0xe5, 0x13, 0xc2, 0x0f, 0x1d, 0x9b, + 0x78, 0x5c, 0x2a, 0xd0, 0x87, 0x6f, 0x9d, 0xd9, 0xa8, 0xb6, 0xc7, 0xb7, 0x9c, 0x6d, 0x6d, 0xad, + 0xf5, 0xf4, 0xfb, 0x8f, 0x2d, 0x4a, 0x2d, 0x87, 0x34, 0x2c, 0xea, 0x60, 0xcf, 0x6a, 0x50, 0x66, + 0xc9, 0x2f, 0x8a, 0xfd, 0xb4, 0xcf, 0x8b, 0x8b, 0x0d, 0xf9, 0x69, 0xf1, 0xec, 0xaf, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x8c, 0x0b, 0x8c, 0x16, 0x7d, 0x0c, 0x00, 0x00, } diff --git a/interop/grpc_testing/test.proto b/interop/grpc_testing/test.proto index f827a3ef2d64..21451047e513 100644 --- a/interop/grpc_testing/test.proto +++ b/interop/grpc_testing/test.proto @@ -214,10 +214,17 @@ message LoadBalancerStatsRequest { } message LoadBalancerStatsResponse { + message RpcsByPeer { + // The number of completed RPCs for each peer. + map rpcs_by_peer = 1; + } + // The number of completed RPCs for each peer. map rpcs_by_peer = 1; // The number of RPCs that failed to record a remote peer. int32 num_failures = 2; + // The number of completed RPCs for each method (UnaryCall or EmptyCall). + map rpcs_by_method = 3; } // A service used to obtain stats for verifying LB behavior. diff --git a/interop/xds/client/client.go b/interop/xds/client/client.go index aff5cfdbf9f4..7792094d54de 100644 --- a/interop/xds/client/client.go +++ b/interop/xds/client/client.go @@ -23,7 +23,9 @@ import ( "context" "flag" "fmt" + "log" "net" + "strings" "sync" "sync/atomic" "time" @@ -31,6 +33,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/grpclog" testpb "google.golang.org/grpc/interop/grpc_testing" + "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" _ "google.golang.org/grpc/xds" ) @@ -40,18 +43,43 @@ type statsWatcherKey struct { endID int32 } +// rpcInfo contains the rpc type and the hostname where the response is received +// from. +type rpcInfo struct { + typ string + hostname string +} + type statsWatcher struct { rpcsByPeer map[string]int32 + rpcsByType map[string]map[string]int32 numFailures int32 remainingRpcs int32 - c chan *testpb.SimpleResponse + chanHosts chan *rpcInfo +} + +func (watcher *statsWatcher) buildResp() *testpb.LoadBalancerStatsResponse { + rpcsByType := make(map[string]*testpb.LoadBalancerStatsResponse_RpcsByPeer, len(watcher.rpcsByType)) + for t, rpcsByPeer := range watcher.rpcsByType { + rpcsByType[t] = &testpb.LoadBalancerStatsResponse_RpcsByPeer{ + RpcsByPeer: rpcsByPeer, + } + } + + return &testpb.LoadBalancerStatsResponse{ + NumFailures: watcher.numFailures + watcher.remainingRpcs, + RpcsByPeer: watcher.rpcsByPeer, + RpcsByMethod: rpcsByType, + } } var ( failOnFailedRPC = flag.Bool("fail_on_failed_rpc", false, "Fail client if any RPCs fail after first success") numChannels = flag.Int("num_channels", 1, "Num of channels") printResponse = flag.Bool("print_response", false, "Write RPC response to stdout") - qps = flag.Int("qps", 1, "QPS per channel") + qps = flag.Int("qps", 1, "QPS per channel, for each type of RPC") + rpc = flag.String("rpc", "UnaryCall", "Types of RPCs to make, ',' separated string. RPCs can be EmptyCall or UnaryCall") + rpcMetadata = flag.String("metadata", "", "The metadata to send with RPC, in format EmptyCall:key1:value1,UnaryCall:key2:value2") rpcTimeout = flag.Duration("rpc_timeout", 20*time.Second, "Per RPC timeout") server = flag.String("server", "localhost:8080", "Address of server to connect to") statsPort = flag.Int("stats_port", 8081, "Port to expose peer distribution stats service") @@ -88,9 +116,10 @@ func (s *statsService) GetClientStats(ctx context.Context, in *testpb.LoadBalanc if !ok { watcher = &statsWatcher{ rpcsByPeer: make(map[string]int32), + rpcsByType: make(map[string]map[string]int32), numFailures: 0, remainingRpcs: in.GetNumRpcs(), - c: make(chan *testpb.SimpleResponse), + chanHosts: make(chan *rpcInfo), } watchers[watcherKey] = watcher } @@ -108,25 +137,86 @@ func (s *statsService) GetClientStats(ctx context.Context, in *testpb.LoadBalanc // Wait until the requested RPCs have all been recorded or timeout occurs. for { select { - case r := <-watcher.c: - if r != nil { - watcher.rpcsByPeer[(*r).GetHostname()]++ + case info := <-watcher.chanHosts: + if info != nil { + watcher.rpcsByPeer[info.hostname]++ + + rpcsByPeerForType := watcher.rpcsByType[info.typ] + if rpcsByPeerForType == nil { + rpcsByPeerForType = make(map[string]int32) + watcher.rpcsByType[info.typ] = rpcsByPeerForType + } + rpcsByPeerForType[info.hostname]++ } else { watcher.numFailures++ } watcher.remainingRpcs-- if watcher.remainingRpcs == 0 { - return &testpb.LoadBalancerStatsResponse{NumFailures: watcher.numFailures + watcher.remainingRpcs, RpcsByPeer: watcher.rpcsByPeer}, nil + return watcher.buildResp(), nil } case <-ctx.Done(): grpclog.Info("Timed out, returning partial stats") - return &testpb.LoadBalancerStatsResponse{NumFailures: watcher.numFailures + watcher.remainingRpcs, RpcsByPeer: watcher.rpcsByPeer}, nil + return watcher.buildResp(), nil + } + } +} + +const ( + unaryCall string = "UnaryCall" + emptyCall string = "EmptyCall" +) + +func parseRPCTypes(rpcStr string) (ret []string) { + if len(rpcStr) == 0 { + return []string{unaryCall} + } + + rpcs := strings.Split(rpcStr, ",") + for _, r := range rpcs { + switch r { + case unaryCall, emptyCall: + ret = append(ret, r) + default: + flag.PrintDefaults() + log.Fatalf("unsupported RPC type: %v", r) + } + } + return +} + +type rpcConfig struct { + typ string + md metadata.MD +} + +// parseRPCMetadata turns EmptyCall:key1:value1 into +// {typ: emptyCall, md: {key1:value1}}. +func parseRPCMetadata(rpcMetadataStr string, rpcs []string) []*rpcConfig { + rpcMetadataSplit := strings.Split(rpcMetadataStr, ",") + rpcsToMD := make(map[string][]string) + for _, rm := range rpcMetadataSplit { + rmSplit := strings.Split(rm, ":") + if len(rmSplit)%2 != 1 { + log.Fatalf("invalid metadata config %v, want EmptyCall:key1:value1", rm) + } + rpcsToMD[rmSplit[0]] = append(rpcsToMD[rmSplit[0]], rmSplit[1:]...) + } + ret := make([]*rpcConfig, 0, len(rpcs)) + for _, rpcT := range rpcs { + rpcC := &rpcConfig{ + typ: rpcT, } + if md := rpcsToMD[string(rpcT)]; len(md) > 0 { + rpcC.md = metadata.Pairs(md...) + } + ret = append(ret, rpcC) } + return ret } func main() { flag.Parse() + rpcCfgs := parseRPCMetadata(*rpcMetadata, parseRPCTypes(*rpc)) lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *statsPort)) if err != nil { @@ -148,16 +238,52 @@ func main() { } ticker := time.NewTicker(time.Second / time.Duration(*qps**numChannels)) defer ticker.Stop() - sendRPCs(clients, ticker) + sendRPCs(clients, rpcCfgs, ticker) } -func sendRPCs(clients []testpb.TestServiceClient, ticker *time.Ticker) { +func makeOneRPC(c testpb.TestServiceClient, cfg *rpcConfig) (*peer.Peer, *rpcInfo, error) { + ctx, cancel := context.WithTimeout(context.Background(), *rpcTimeout) + defer cancel() + + if len(cfg.md) != 0 { + ctx = metadata.NewOutgoingContext(ctx, cfg.md) + } + info := rpcInfo{typ: cfg.typ} + + var ( + p peer.Peer + header metadata.MD + err error + ) + switch cfg.typ { + case unaryCall: + var resp *testpb.SimpleResponse + resp, err = c.UnaryCall(ctx, &testpb.SimpleRequest{FillServerId: true}, grpc.Peer(&p), grpc.Header(&header)) + // For UnaryCall, also read hostname from response, in case the server + // isn't updated to send headers. + if resp != nil { + info.hostname = resp.Hostname + } + case emptyCall: + _, err = c.EmptyCall(ctx, &testpb.Empty{}, grpc.Peer(&p), grpc.Header(&header)) + } + if err != nil { + return nil, nil, err + } + + hosts := header["hostname"] + if len(hosts) > 0 { + info.hostname = hosts[0] + } + return &p, &info, err +} + +func sendRPCs(clients []testpb.TestServiceClient, cfgs []*rpcConfig, ticker *time.Ticker) { var i int for range ticker.C { go func(i int) { - c := clients[i] - ctx, cancel := context.WithTimeout(context.Background(), *rpcTimeout) - p := new(peer.Peer) + // Get and increment request ID, and save a list of watchers that + // are interested in this RPC. mu.Lock() savedRequestID := currentRequestID currentRequestID++ @@ -168,23 +294,35 @@ func sendRPCs(clients []testpb.TestServiceClient, ticker *time.Ticker) { } } mu.Unlock() - r, err := c.UnaryCall(ctx, &testpb.SimpleRequest{FillServerId: true}, grpc.Peer(p)) - success := err == nil - cancel() + c := clients[i] - for _, watcher := range savedWatchers { - watcher.c <- r - } + for _, cfg := range cfgs { + p, info, err := makeOneRPC(c, cfg) - if err != nil && *failOnFailedRPC && hasRPCSucceeded() { - grpclog.Fatalf("RPC failed: %v", err) - } - if success { + for _, watcher := range savedWatchers { + // This sends an empty string if the RPC failed. + watcher.chanHosts <- info + } + if err != nil && *failOnFailedRPC && hasRPCSucceeded() { + grpclog.Fatalf("RPC failed: %v", err) + } + if err == nil { + setRPCSucceeded() + } if *printResponse { - fmt.Printf("Greeting: Hello world, this is %s, from %v\n", r.GetHostname(), p.Addr) + if err == nil { + if cfg.typ == unaryCall { + // Need to keep this format, because some tests are + // relying on stdout. + fmt.Printf("Greeting: Hello world, this is %s, from %v\n", info.hostname, p.Addr) + } else { + fmt.Printf("RPC %q, from host %s, addr %v\n", cfg.typ, info.hostname, p.Addr) + } + } else { + fmt.Printf("RPC %q, failed with %v\n", cfg.typ, err) + } } - setRPCSucceeded() } }(i) i = (i + 1) % len(clients) diff --git a/interop/xds/server/server.go b/interop/xds/server/server.go index 34ada6b542e6..cfb2016f8670 100644 --- a/interop/xds/server/server.go +++ b/interop/xds/server/server.go @@ -30,6 +30,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/grpclog" testpb "google.golang.org/grpc/interop/grpc_testing" + "google.golang.org/grpc/metadata" ) var ( @@ -50,7 +51,13 @@ type server struct { testpb.UnimplementedTestServiceServer } +func (s *server) EmptyCall(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) { + grpc.SetHeader(ctx, metadata.Pairs("hostname", hostname)) + return &testpb.Empty{}, nil +} + func (s *server) UnaryCall(ctx context.Context, in *testpb.SimpleRequest) (*testpb.SimpleResponse, error) { + grpc.SetHeader(ctx, metadata.Pairs("hostname", hostname)) return &testpb.SimpleResponse{ServerId: *serverID, Hostname: hostname}, nil } diff --git a/security/advancedtls/advancedtls.go b/security/advancedtls/advancedtls.go index 745938ac5295..e028c623ba43 100644 --- a/security/advancedtls/advancedtls.go +++ b/security/advancedtls/advancedtls.go @@ -156,7 +156,7 @@ type ClientOptions struct { // Certificates or GetClientCertificate indicates the certificates sent from // the server to the client to prove server's identities. The rules for setting // these two fields are: -// Either Certificates or GetCertificate must be set; the other will be ignored. +// Either Certificates or GetCertificates must be set; the other will be ignored. type ServerOptions struct { // If field Certificates is set, field GetClientCertificate will be ignored. // The server will use Certificates every time when asked for a certificate, @@ -166,7 +166,7 @@ type ServerOptions struct { // invoke this function every time asked to present certificates to the // client when a new connection is established. This is known as peer // certificate reloading. - GetCertificate func(*tls.ClientHelloInfo) (*tls.Certificate, error) + GetCertificates func(*tls.ClientHelloInfo) ([]*tls.Certificate, error) // VerifyPeer is a custom verification check after certificate signature // check. // If this is set, we will perform this customized check after doing the @@ -210,8 +210,8 @@ func (o *ClientOptions) config() (*tls.Config, error) { } func (o *ServerOptions) config() (*tls.Config, error) { - if o.Certificates == nil && o.GetCertificate == nil { - return nil, fmt.Errorf("either Certificates or GetCertificate must be specified") + if o.Certificates == nil && o.GetCertificates == nil { + return nil, fmt.Errorf("either Certificates or GetCertificates must be specified") } if o.RequireClientCert && o.VType == SkipVerification && o.VerifyPeer == nil { return nil, fmt.Errorf( @@ -234,9 +234,15 @@ func (o *ServerOptions) config() (*tls.Config, error) { clientAuth = tls.RequireAnyClientCert } config := &tls.Config{ - ClientAuth: clientAuth, - Certificates: o.Certificates, - GetCertificate: o.GetCertificate, + ClientAuth: clientAuth, + Certificates: o.Certificates, + } + if o.GetCertificates != nil { + // GetCertificate is only able to perform SNI logic for go1.10 and above. + // It will return the first certificate in o.GetCertificates for go1.9. + config.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) { + return buildGetCertificates(clientHello, o) + } } if clientCAs != nil { config.ClientCAs = clientCAs diff --git a/security/advancedtls/advancedtls_integration_test.go b/security/advancedtls/advancedtls_integration_test.go index 5f8c25f681b3..3f9f6218035a 100644 --- a/security/advancedtls/advancedtls_integration_test.go +++ b/security/advancedtls/advancedtls_integration_test.go @@ -197,7 +197,7 @@ func TestEnd2End(t *testing.T) { clientVerifyFunc CustomVerificationFunc clientVType VerificationType serverCert []tls.Certificate - serverGetCert func(*tls.ClientHelloInfo) (*tls.Certificate, error) + serverGetCert func(*tls.ClientHelloInfo) ([]*tls.Certificate, error) serverRoot *x509.CertPool serverGetRoot func(params *GetRootCAsParams) (*GetRootCAsResults, error) serverVerifyFunc CustomVerificationFunc @@ -271,12 +271,12 @@ func TestEnd2End(t *testing.T) { return &VerificationResults{}, nil }, clientVType: CertVerification, - serverGetCert: func(*tls.ClientHelloInfo) (*tls.Certificate, error) { + serverGetCert: func(*tls.ClientHelloInfo) ([]*tls.Certificate, error) { switch stage.read() { case 0: - return &cs.serverPeer1, nil + return []*tls.Certificate{&cs.serverPeer1}, nil default: - return &cs.serverPeer2, nil + return []*tls.Certificate{&cs.serverPeer2}, nil } }, serverRoot: cs.serverTrust1, @@ -336,12 +336,12 @@ func TestEnd2End(t *testing.T) { return nil, fmt.Errorf("custom authz check fails") }, clientVType: CertVerification, - serverGetCert: func(*tls.ClientHelloInfo) (*tls.Certificate, error) { + serverGetCert: func(*tls.ClientHelloInfo) ([]*tls.Certificate, error) { switch stage.read() { case 0: - return &cs.serverPeer1, nil + return []*tls.Certificate{&cs.serverPeer1}, nil default: - return &cs.serverPeer2, nil + return []*tls.Certificate{&cs.serverPeer2}, nil } }, serverRoot: cs.serverTrust1, @@ -388,8 +388,8 @@ func TestEnd2End(t *testing.T) { t.Run(test.desc, func(t *testing.T) { // Start a server using ServerOptions in another goroutine. serverOptions := &ServerOptions{ - Certificates: test.serverCert, - GetCertificate: test.serverGetCert, + Certificates: test.serverCert, + GetCertificates: test.serverGetCert, RootCertificateOptions: RootCertificateOptions{ RootCACerts: test.serverRoot, GetRootCAs: test.serverGetRoot, diff --git a/security/advancedtls/advancedtls_test.go b/security/advancedtls/advancedtls_test.go index 263bf7df418c..b2514547c174 100644 --- a/security/advancedtls/advancedtls_test.go +++ b/security/advancedtls/advancedtls_test.go @@ -102,7 +102,7 @@ func TestClientServerHandshake(t *testing.T) { clientExpectHandshakeError bool serverMutualTLS bool serverCert []tls.Certificate - serverGetCert func(*tls.ClientHelloInfo) (*tls.Certificate, error) + serverGetCert func(*tls.ClientHelloInfo) ([]*tls.Certificate, error) serverRoot *x509.CertPool serverGetRoot func(params *GetRootCAsParams) (*GetRootCAsResults, error) serverVerifyFunc CustomVerificationFunc @@ -279,8 +279,8 @@ func TestClientServerHandshake(t *testing.T) { clientVerifyFunc: clientVerifyFuncGood, clientVType: CertVerification, serverMutualTLS: true, - serverGetCert: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { - return &serverPeerCert, nil + serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) { + return []*tls.Certificate{&serverPeerCert}, nil }, serverGetRoot: getRootCAsForServer, serverVerifyFunc: serverVerifyFunc, @@ -300,8 +300,8 @@ func TestClientServerHandshake(t *testing.T) { clientVerifyFunc: clientVerifyFuncGood, clientVType: CertVerification, serverMutualTLS: true, - serverGetCert: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { - return &serverPeerCert, nil + serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) { + return []*tls.Certificate{&serverPeerCert}, nil }, serverGetRoot: getRootCAsForServer, serverVerifyFunc: serverVerifyFunc, @@ -322,8 +322,8 @@ func TestClientServerHandshake(t *testing.T) { clientVType: CertVerification, clientExpectHandshakeError: true, serverMutualTLS: true, - serverGetCert: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { - return &serverPeerCert, nil + serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) { + return []*tls.Certificate{&serverPeerCert}, nil }, serverGetRoot: getRootCAsForServer, serverVerifyFunc: serverVerifyFunc, @@ -344,8 +344,8 @@ func TestClientServerHandshake(t *testing.T) { clientVerifyFunc: clientVerifyFuncGood, clientVType: CertVerification, serverMutualTLS: true, - serverGetCert: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { - return &clientPeerCert, nil + serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) { + return []*tls.Certificate{&clientPeerCert}, nil }, serverGetRoot: getRootCAsForServer, serverVerifyFunc: serverVerifyFunc, @@ -366,8 +366,8 @@ func TestClientServerHandshake(t *testing.T) { clientVType: CertVerification, clientExpectHandshakeError: true, serverMutualTLS: true, - serverGetCert: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { - return &serverPeerCert, nil + serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) { + return []*tls.Certificate{&serverPeerCert}, nil }, serverGetRoot: getRootCAsForClient, serverVerifyFunc: serverVerifyFunc, @@ -402,8 +402,8 @@ func TestClientServerHandshake(t *testing.T) { } // Start a server using ServerOptions in another goroutine. serverOptions := &ServerOptions{ - Certificates: test.serverCert, - GetCertificate: test.serverGetCert, + Certificates: test.serverCert, + GetCertificates: test.serverGetCert, RootCertificateOptions: RootCertificateOptions{ RootCACerts: test.serverRoot, GetRootCAs: test.serverGetRoot, diff --git a/security/advancedtls/go.mod b/security/advancedtls/go.mod index 392985d74469..f21b428ef4c0 100644 --- a/security/advancedtls/go.mod +++ b/security/advancedtls/go.mod @@ -4,7 +4,7 @@ go 1.13 require ( github.com/golang/protobuf v1.3.5 // indirect - github.com/google/go-cmp v0.4.0 // indirect + github.com/google/go-cmp v0.4.0 golang.org/x/net v0.0.0-20200602114024-627f9648deb9 // indirect golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 // indirect golang.org/x/text v0.3.3 // indirect diff --git a/security/advancedtls/sni_110.go b/security/advancedtls/sni_110.go new file mode 100644 index 000000000000..5c9a6ae13a0f --- /dev/null +++ b/security/advancedtls/sni_110.go @@ -0,0 +1,53 @@ +// +build go1.10 + +/* + * + * Copyright 2020 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 advancedtls + +import ( + "crypto/tls" + "fmt" +) + +// buildGetCertificates returns the certificate that matches the SNI field +// for the given ClientHelloInfo, defaulting to the first element of o.GetCertificates. +func buildGetCertificates(clientHello *tls.ClientHelloInfo, o *ServerOptions) (*tls.Certificate, error) { + if o.GetCertificates == nil { + return nil, fmt.Errorf("function GetCertificates must be specified") + } + certificates, err := o.GetCertificates(clientHello) + if err != nil { + return nil, err + } + if len(certificates) == 0 { + return nil, fmt.Errorf("no certificates configured") + } + // If users pass in only one certificate, return that certificate. + if len(certificates) == 1 { + return certificates[0], nil + } + // Choose the SNI certificate using SupportsCertificate. + for _, cert := range certificates { + if err := clientHello.SupportsCertificate(cert); err == nil { + return cert, nil + } + } + // If nothing matches, return the first certificate. + return certificates[0], nil +} diff --git a/xds/internal/client/envconfig.go b/security/advancedtls/sni_before_110.go similarity index 52% rename from xds/internal/client/envconfig.go rename to security/advancedtls/sni_before_110.go index 40f448e63711..180e3a05d494 100644 --- a/xds/internal/client/envconfig.go +++ b/security/advancedtls/sni_before_110.go @@ -1,3 +1,5 @@ +// +build !go1.10 + /* * * Copyright 2020 gRPC authors. @@ -16,18 +18,24 @@ * */ -package client +package advancedtls import ( - "os" - "strings" + "crypto/tls" + "fmt" ) -// TODO: there are multiple env variables, GRPC_XDS_BOOTSTRAP and -// GRPC_XDS_EXPERIMENTAL_V3_SUPPORT, and this. Move all env variables into a -// separate package. -const routingEnabledConfigStr = "GRPC_XDS_EXPERIMENTAL_ROUTING" - -// routing is enabled only if env variable is set to true. The default is false. -// We may flip the default later. -var routingEnabled = strings.EqualFold(os.Getenv(routingEnabledConfigStr), "true") +// buildGetCertificates returns the first element of o.GetCertificates. +func buildGetCertificates(clientHello *tls.ClientHelloInfo, o *ServerOptions) (*tls.Certificate, error) { + if o.GetCertificates == nil { + return nil, fmt.Errorf("function GetCertificates must be specified") + } + certificates, err := o.GetCertificates(clientHello) + if err != nil { + return nil, err + } + if len(certificates) == 0 { + return nil, fmt.Errorf("no certificates configured") + } + return certificates[0], nil +} diff --git a/security/advancedtls/sni_test_110.go b/security/advancedtls/sni_test_110.go new file mode 100644 index 000000000000..130ccde59050 --- /dev/null +++ b/security/advancedtls/sni_test_110.go @@ -0,0 +1,108 @@ +// +build go1.10 + +/* + * + * Copyright 2019 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 advancedtls + +import ( + "crypto/tls" + "testing" + + "github.com/google/go-cmp/cmp" + "google.golang.org/grpc/security/advancedtls/testdata" +) + +// TestGetCertificatesSNI tests SNI logic for go1.10 and above. +func TestGetCertificatesSNI(t *testing.T) { + // Load server certificates for setting the serverGetCert callback function. + serverCert1, err := tls.LoadX509KeyPair(testdata.Path("server_cert_1.pem"), testdata.Path("server_key_1.pem")) + if err != nil { + t.Fatalf("tls.LoadX509KeyPair(server_cert_1.pem, server_key_1.pem) failed: %v", err) + } + serverCert2, err := tls.LoadX509KeyPair(testdata.Path("server_cert_2.pem"), testdata.Path("server_key_2.pem")) + if err != nil { + t.Fatalf("tls.LoadX509KeyPair(server_cert_2.pem, server_key_2.pem) failed: %v", err) + } + serverCert3, err := tls.LoadX509KeyPair(testdata.Path("server_cert_3.pem"), testdata.Path("server_key_3.pem")) + if err != nil { + t.Fatalf("tls.LoadX509KeyPair(server_cert_3.pem, server_key_3.pem) failed: %v", err) + } + + tests := []struct { + desc string + serverGetCert func(*tls.ClientHelloInfo) ([]*tls.Certificate, error) + serverName string + wantCert tls.Certificate + }{ + { + desc: "Select serverCert1", + serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) { + return []*tls.Certificate{&serverCert1, &serverCert2, &serverCert3}, nil + }, + // "foo.bar.com" is the common name on server certificate server_cert_1.pem. + serverName: "foo.bar.com", + wantCert: serverCert1, + }, + { + desc: "Select serverCert2", + serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) { + return []*tls.Certificate{&serverCert1, &serverCert2, &serverCert3}, nil + }, + // "foo.bar.server2.com" is the common name on server certificate server_cert_2.pem. + serverName: "foo.bar.server2.com", + wantCert: serverCert2, + }, + { + desc: "Select serverCert3", + serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) { + return []*tls.Certificate{&serverCert1, &serverCert2, &serverCert3}, nil + }, + // "google.com" is one of the DNS names on server certificate server_cert_3.pem. + serverName: "google.com", + wantCert: serverCert3, + }, + } + for _, test := range tests { + test := test + t.Run(test.desc, func(t *testing.T) { + serverOptions := &ServerOptions{ + GetCertificates: test.serverGetCert, + } + serverConfig, err := serverOptions.config() + if err != nil { + t.Fatalf("serverOptions.config() failed: %v", err) + } + pointFormatUncompressed := uint8(0) + clientHello := &tls.ClientHelloInfo{ + CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA}, + ServerName: test.serverName, + SupportedCurves: []tls.CurveID{tls.CurveP256}, + SupportedPoints: []uint8{pointFormatUncompressed}, + SupportedVersions: []uint16{tls.VersionTLS10}, + } + gotCertificate, err := serverConfig.GetCertificate(clientHello) + if err != nil { + t.Fatalf("serverConfig.GetCertificate(clientHello) failed: %v", err) + } + if !cmp.Equal(gotCertificate, test.wantCert, cmp.AllowUnexported(tls.Certificate{})) { + t.Errorf("GetCertificates() = %v, want %v", gotCertificate, test.wantCert) + } + }) + } +} diff --git a/security/advancedtls/sni_test_before_110.go b/security/advancedtls/sni_test_before_110.go new file mode 100644 index 000000000000..e31e2e6ee759 --- /dev/null +++ b/security/advancedtls/sni_test_before_110.go @@ -0,0 +1,108 @@ +// +build !go1.10 + +/* + * + * Copyright 2019 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 advancedtls + +import ( + "crypto/tls" + "testing" + + "github.com/google/go-cmp/cmp" + "google.golang.org/grpc/security/advancedtls/testdata" +) + +// TestGetCertificatesSNI tests SNI logic for go1.9. +func TestGetCertificatesSNI(t *testing.T) { + // Load server certificates for setting the serverGetCert callback function. + serverCert1, err := tls.LoadX509KeyPair(testdata.Path("server_cert_1.pem"), testdata.Path("server_key_1.pem")) + if err != nil { + t.Fatalf("tls.LoadX509KeyPair(server_cert_1.pem, server_key_1.pem) failed: %v", err) + } + serverCert2, err := tls.LoadX509KeyPair(testdata.Path("server_cert_2.pem"), testdata.Path("server_key_2.pem")) + if err != nil { + t.Fatalf("tls.LoadX509KeyPair(server_cert_2.pem, server_key_2.pem) failed: %v", err) + } + serverCert3, err := tls.LoadX509KeyPair(testdata.Path("server_cert_3.pem"), testdata.Path("server_key_3.pem")) + if err != nil { + t.Fatalf("tls.LoadX509KeyPair(server_cert_3.pem, server_key_3.pem) failed: %v", err) + } + + tests := []struct { + desc string + serverGetCert func(*tls.ClientHelloInfo) ([]*tls.Certificate, error) + serverName string + wantCert tls.Certificate + }{ + { + desc: "Select serverCert1", + serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) { + return []*tls.Certificate{&serverCert1, &serverCert2, &serverCert3}, nil + }, + // "foo.bar.com" is the common name on server certificate server_cert_1.pem. + serverName: "foo.bar.com", + wantCert: serverCert1, + }, + { + desc: "Select serverCert2", + serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) { + return []*tls.Certificate{&serverCert1, &serverCert2, &serverCert3}, nil + }, + // "foo.bar.server2.com" is the common name on server certificate server_cert_2.pem. + serverName: "foo.bar.server2.com", + wantCert: serverCert1, + }, + { + desc: "Select serverCert3", + serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) { + return []*tls.Certificate{&serverCert1, &serverCert2, &serverCert3}, nil + }, + // "google.com" is one of the DNS names on server certificate server_cert_3.pem. + serverName: "google.com", + wantCert: serverCert1, + }, + } + for _, test := range tests { + test := test + t.Run(test.desc, func(t *testing.T) { + serverOptions := &ServerOptions{ + GetCertificates: test.serverGetCert, + } + serverConfig, err := serverOptions.config() + if err != nil { + t.Fatalf("serverOptions.config() failed: %v", err) + } + pointFormatUncompressed := uint8(0) + clientHello := &tls.ClientHelloInfo{ + CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA}, + ServerName: test.serverName, + SupportedCurves: []tls.CurveID{tls.CurveP256}, + SupportedPoints: []uint8{pointFormatUncompressed}, + SupportedVersions: []uint16{tls.VersionTLS10}, + } + gotCertificate, err := serverConfig.GetCertificate(clientHello) + if err != nil { + t.Fatalf("serverConfig.GetCertificate(clientHello) failed: %v", err) + } + if !cmp.Equal(gotCertificate, test.wantCert, cmp.AllowUnexported(tls.Certificate{})) { + t.Errorf("GetCertificates() = %v, want %v", gotCertificate, test.wantCert) + } + }) + } +} diff --git a/security/advancedtls/testdata/server_cert_1.txt b/security/advancedtls/testdata/server_cert_1.txt new file mode 100644 index 000000000000..5367569d0528 --- /dev/null +++ b/security/advancedtls/testdata/server_cert_1.txt @@ -0,0 +1,90 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = CA, L = SVL, O = Internet Widgits Pty Ltd + Validity + Not Before: Nov 4 21:43:00 2019 GMT + Not After : Aug 18 21:43:00 2293 GMT + Subject: C = US, ST = CA, L = DUMMYCITY, O = Internet Widgits Pty Ltd, CN = foo.bar.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (4096 bit) + Modulus: + 00:ec:3f:24:2d:91:3a:bd:c3:fc:15:72:42:b3:fb: + 28:e6:04:a3:be:26:20:e6:ea:30:a8:aa:48:78:36: + 0e:0b:99:29:3b:4b:f9:f1:d5:bf:bd:0c:13:7c:ea: + 52:06:f4:bc:34:9e:2b:c0:b4:82:2c:87:fa:2f:e2: + cd:7c:d7:b9:e1:8f:04:71:6d:85:77:ae:18:40:e4: + b1:3a:4a:6b:e5:33:bf:3e:65:db:cf:94:64:87:1a: + 20:46:c0:37:3a:9f:93:3f:d4:4f:ac:c4:e4:e0:28: + b6:0f:28:53:2a:cf:b9:fe:50:f2:ef:47:dc:7e:b6: + 60:c2:47:85:b8:cb:ca:48:5b:fa:9f:8a:97:30:01: + f4:b3:51:0f:68:e1:60:ab:2f:a0:ad:fc:f0:10:4f: + 60:e1:92:db:be:83:04:5c:40:87:ce:51:3e:9a:9e: + d6:1c:1b:19:cb:8c:c2:6c:57:74:6f:7b:af:94:3d: + 53:ad:17:a5:99:69:7c:41:f5:3e:7a:5b:48:c7:78: + ff:d7:3b:a8:1f:f7:30:e7:83:26:78:e2:cb:a2:8f: + 58:92:61:cd:ca:e9:b8:d1:80:c0:40:58:e9:d8:d3: + 42:64:82:8f:e4:0c:b9:b1:36:db:9f:65:3f:3f:5b: + 24:59:31:b3:60:0c:fa:41:5a:1b:b8:9d:ec:99:37: + 90:fa:b5:e7:3f:cb:7c:e0:f9:ed:ea:27:ce:15:24: + c7:77:3b:45:45:2d:19:8e:2e:7f:65:0e:85:df:66: + 50:69:24:2c:a4:6a:07:e5:3f:eb:28:84:53:94:4d: + 5f:9c:a8:65:a6:50:4c:c0:35:06:40:6a:a5:62:b1: + 93:60:e5:1c:85:28:34:9b:29:81:6f:e2:4f:cd:15: + 30:b9:19:d7:4b:bb:30:0c:4b:2d:64:fe:3b:dd:0e: + a4:25:2c:4a:5c:de:d7:74:1f:5e:93:7b:1c:e8:c8: + fa:72:1f:4a:eb:8d:3f:98:e4:55:98:b8:e0:8a:29: + 92:33:af:75:6b:05:84:05:d3:0c:2c:07:78:bc:0e: + b2:6d:a7:00:35:c4:53:1f:7b:e6:ba:07:72:a8:24: + c1:0a:a7:c4:46:e6:f2:6f:3a:79:23:00:0b:b8:e5: + 1f:e0:e2:ee:c6:13:a3:57:d9:86:1a:95:f7:a3:04: + f1:46:d5:5f:21:d2:aa:d2:30:fb:f6:cb:e0:da:24: + c6:c3:30:2f:d2:1f:21:fe:bc:0f:99:ac:ac:9b:65: + 9b:e4:83:9a:00:b8:2f:40:fc:3b:42:d3:7a:e8:b7: + 52:d7:f4:67:2a:a5:f7:eb:78:f1:0a:56:8b:56:12: + d5:48:d8:48:70:ab:b8:69:5a:21:d3:71:b0:59:9d: + 17:b4:4b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + C0:82:DA:FA:69:46:30:AE:FF:6F:CD:BB:93:49:94:A6:D0:E2:17:EB + X509v3 Authority Key Identifier: + keyid:5A:A5:DA:B1:99:D4:E5:0E:E6:1E:94:EA:FF:FC:62:E2:ED:09:F1:06 + + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Key Encipherment + Signature Algorithm: sha256WithRSAEncryption + 36:fd:cf:ec:f5:20:4b:52:dc:2e:38:f3:92:b1:e4:b6:a1:06: + 86:aa:2d:c0:e6:f5:0a:58:97:a9:e3:be:13:09:61:79:ed:d4: + 41:83:26:ad:ee:0b:43:83:d1:dd:19:1a:e8:7b:b2:1f:fe:d4: + c1:57:7d:6d:6b:d4:42:ea:7d:cd:34:8c:a4:1f:5b:3b:fa:de: + bb:2f:ae:56:b6:18:e5:53:a9:a3:99:58:ad:36:be:19:54:61: + 0d:52:b6:a7:53:fc:60:e5:ff:f5:7f:82:3f:c1:49:06:cd:b2: + af:25:ee:de:bd:e0:e5:5e:ad:0b:dc:2e:b1:ec:7a:52:6f:9d: + e0:b9:84:18:db:49:53:ee:df:93:ee:8b:9d:9b:8e:3b:2a:82: + 86:7f:45:c8:dd:d1:b0:40:17:ed:63:52:a1:5b:6e:d3:5c:a2: + 72:05:fb:3a:39:71:0d:b4:2c:9d:15:23:1b:1f:8d:ac:89:dc: + c9:56:f2:19:c7:f3:2f:bb:d5:de:40:17:f1:52:ea:e8:93:ff: + 56:43:f5:1d:cb:c0:51:52:25:d7:b0:81:a9:0e:4d:92:24:e7: + 10:81:c7:31:26:ac:cb:66:c1:3f:f6:5f:69:7b:74:87:0d:b0: + 8c:27:d4:24:29:59:e9:5b:a2:cb:0c:c0:f5:9b:1d:42:38:6b: + e3:c3:43:1e:ba:df:b1:51:0a:b7:33:55:26:39:01:2f:9f:c7: + 88:ac:2f:4a:89:f3:69:de:72:43:48:49:08:59:36:86:84:09: + db:6a:82:84:3e:71:6a:9d:f9:bd:d8:b5:1e:7c:2c:29:e1:27: + 45:4c:47:5b:88:b8:e6:fa:9d:9b:ff:d4:e9:8d:2d:5e:64:7f: + 27:87:b2:8c:d8:7e:f5:52:3c:c4:d8:30:03:24:d7:ac:f8:53: + 91:80:98:42:24:5a:6b:cb:34:48:57:e0:82:ac:96:d9:55:6c: + c2:c3:8c:19:7c:56:39:0a:a8:f1:b8:77:64:70:83:a8:04:c8: + 3a:5d:0b:00:4c:e5:ba:f1:40:e5:57:cd:d9:67:48:21:e9:9c: + d3:f2:b8:01:b8:d1:c0:d1:3a:44:c0:97:db:e6:bc:8f:2e:33: + d5:e2:38:3d:d7:7b:50:13:01:36:28:61:cc:28:98:3c:f8:21: + 5d:8c:fe:f5:d0:ab:e0:60:ec:36:22:8d:0b:71:30:1b:3d:56: + ae:96:e9:d2:89:c2:43:8b:ef:25:b7:d6:0d:82:e6:5a:c6:91: + 8a:ad:8c:28:2a:2b:5c:4e:a1:de:cb:7d:cb:29:11:a2:66:c8: + a1:33:35:75:16:fe:28:0b:78:31:0a:1f:fa:d0:a8:f4:f1:69: + c7:97:1e:5d:fb:53:08:b5 diff --git a/security/advancedtls/testdata/server_cert_2.txt b/security/advancedtls/testdata/server_cert_2.txt new file mode 100644 index 000000000000..8962204ff348 --- /dev/null +++ b/security/advancedtls/testdata/server_cert_2.txt @@ -0,0 +1,91 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7 (0x7) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = CA, O = Internet Widgits Pty Ltd, CN = foo.bar.client2.trust.com + Validity + Not Before: Jan 9 22:51:54 2020 GMT + Not After : Oct 23 22:51:54 2293 GMT + Subject: C = US, ST = CA, O = Internet Widgits Pty Ltd, CN = foo.bar.server2.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (4096 bit) + Modulus: + 00:b1:0b:d3:7e:5b:61:30:db:b0:5f:3f:6d:d2:e0: + 3b:c6:4c:88:95:f5:7e:fd:cd:aa:20:5d:08:b9:6e: + 41:db:c4:ed:0d:f8:bc:cb:b4:ee:c5:87:11:05:a0: + ac:12:3b:4e:0b:4c:e4:43:e4:17:89:c1:ae:b4:13: + 58:1c:31:58:6a:f2:01:ed:df:66:e9:f9:2e:9c:c5: + 85:e6:02:db:36:f4:f3:07:39:75:30:f1:b5:55:5b: + 46:2f:87:b0:d4:a0:ab:57:df:30:45:ae:bd:b0:49: + 9a:fc:ba:5e:bc:d0:5d:86:f4:24:45:4a:d5:4d:5b: + b6:ba:e8:b7:a1:3b:c3:2f:46:2e:b3:ad:2c:63:03: + df:cb:f4:56:62:91:bd:bc:23:00:af:a2:7a:3d:6f: + f1:33:81:60:0e:bc:20:f5:8a:49:5f:ec:58:bc:64: + d5:47:36:a0:2b:b8:1f:76:25:01:89:3e:ff:52:69: + 95:03:8f:bb:14:2f:1a:38:a3:9f:c1:45:20:22:77: + 70:97:5e:25:51:b8:3d:5d:89:7a:bb:15:12:cd:1d: + 96:d2:9c:72:67:12:85:72:6e:27:7a:ef:25:da:af: + 49:26:8d:eb:a0:34:a4:4d:64:c3:63:33:77:5d:ad: + 53:c7:ee:51:32:7b:cc:43:bb:86:8d:f9:52:ba:35: + 23:0e:30:5d:dc:3b:25:63:c1:e3:5f:4b:b2:02:fc: + fe:5b:18:7f:84:aa:f3:71:e4:16:b5:98:bc:73:c5: + 58:13:41:38:eb:f3:a2:fa:8c:98:bd:f1:10:ee:b6: + fe:7e:a5:81:c7:5e:f2:72:54:8e:db:09:f0:35:42: + ca:b7:86:c2:48:b2:c6:18:08:ac:d1:f0:5d:de:b0: + b8:25:8b:3b:bd:61:48:0f:71:3f:ed:97:72:02:c9: + 44:5d:0c:00:fc:30:ca:5d:1c:e5:13:1b:3a:d0:ce: + d9:36:a0:db:f5:c2:ad:a6:95:26:4e:7b:29:2d:fc: + c4:04:1d:47:6e:03:59:68:1e:7a:20:6d:e8:a8:e1: + 3c:57:59:f8:3d:2f:16:61:7e:24:e5:13:ca:48:0a: + e6:f0:60:a3:2d:93:0b:8f:93:eb:b5:d1:06:26:52: + c0:63:1f:fc:9b:73:fe:91:c3:04:40:32:8d:09:d5: + 9e:c4:f6:0b:61:3d:9f:a1:d7:94:a2:e1:3d:b6:bb: + 60:26:74:89:33:25:18:0f:c3:88:db:10:5e:a0:5b: + f4:ee:d0:18:ab:36:50:c5:44:9b:6d:ba:ea:e2:6e: + 52:3a:55:49:a3:72:ae:04:af:1d:f6:f2:83:27:17: + 8b:9a:98:0a:f5:44:b1:c8:f2:a9:c8:ed:b0:75:ca: + 52:25:f3 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 74:BD:18:0B:32:AF:D0:51:8E:4C:4C:8D:B2:F6:4E:B8:6D:AB:BD:BA + X509v3 Authority Key Identifier: + keyid:01:74:A9:44:61:3D:7A:BB:C2:32:CD:D0:ED:20:DA:3A:C4:C6:02:E8 + + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Key Encipherment + Signature Algorithm: sha256WithRSAEncryption + b5:63:0c:d8:ed:af:74:2d:4c:94:36:41:05:2a:f2:ef:45:e5: + 6a:0c:76:0c:f3:90:25:e0:54:56:f3:26:23:95:7e:24:74:6b: + fd:02:0a:bc:33:ba:e8:e8:8f:a3:b3:85:2e:59:4c:cf:e3:85: + 1a:d6:70:5c:7c:86:e2:7a:11:99:a8:fa:43:9a:bf:50:54:00: + 9e:6a:7b:72:7f:c5:20:89:6e:18:6c:46:64:ce:44:44:47:4d: + 87:b5:fc:cf:f3:b9:9f:45:a3:cb:b0:91:00:96:2d:29:68:8b: + ff:c7:e0:f1:b7:8d:31:c2:01:be:5b:51:1d:af:42:b1:17:22: + bc:91:e4:d9:b9:96:6d:64:40:79:6c:71:ed:f6:e5:49:16:0a: + e3:bc:18:95:2e:89:ba:c4:a5:ce:ba:ab:3a:32:eb:bc:d8:91: + cd:f2:ee:d1:fc:67:3a:51:00:92:bd:b8:68:0b:54:04:d5:07: + 0b:97:11:2c:42:64:7c:47:c1:68:b4:eb:21:c4:e4:ad:17:a7: + 16:b9:e0:e6:cd:04:c6:89:36:40:d4:4b:c3:f7:7e:26:6b:3a: + d7:68:b3:b2:da:00:65:13:c8:fa:d0:1c:2e:10:ba:71:3e:0f: + aa:8b:d0:ff:b7:3e:83:9c:bc:b3:d1:52:0c:9f:3f:21:4a:10: + dc:8f:ab:38:45:d4:2c:2a:15:2d:71:45:fe:91:a2:d8:d9:dd: + 0c:dc:a7:d9:cd:1b:f5:35:fe:14:ba:c5:1f:ed:ee:fb:87:cc: + 87:a1:08:c2:2e:ff:5d:af:b3:3d:6e:11:94:79:0b:28:e6:83: + 4e:fc:28:8f:7f:00:85:79:7f:3a:d1:07:ee:6e:fa:94:c4:0b: + 4b:2c:05:b1:68:00:e8:37:bc:b8:b2:03:5c:5a:ca:13:f2:68: + 57:df:ac:fc:da:be:27:24:7e:6d:c4:a9:53:2d:f2:43:0e:30: + 9c:82:d5:fb:f1:a2:0a:83:e0:a5:d8:9f:09:3e:99:c8:39:d6: + 69:6d:d6:c2:27:70:59:05:3c:3c:7d:d6:41:6a:b4:9c:1f:70: + 7e:3e:ee:6f:67:de:95:1d:eb:31:8b:11:c8:0d:a1:25:4e:08: + ef:3a:11:2d:a7:98:0d:a1:d9:30:2d:da:d2:a0:05:6b:34:38: + a6:87:b2:bd:0f:9c:51:cc:e0:2e:a2:1b:a3:a0:a6:eb:1f:0a: + 22:70:59:f0:0b:c9:bd:94:4e:1d:65:3b:99:5d:8e:6c:18:82: + 1d:b5:cc:6f:14:21:c4:89:07:9b:81:1d:9a:79:ff:bf:fd:ce: + e4:77:11:0f:47:21:dc:d9:79:f3:40:26:56:5c:b4:86:32:8e: + 28:b9:14:e7:b3:fe:86:47 + \ No newline at end of file diff --git a/security/advancedtls/testdata/server_cert_3.pem b/security/advancedtls/testdata/server_cert_3.pem new file mode 100644 index 000000000000..bfd2d095b227 --- /dev/null +++ b/security/advancedtls/testdata/server_cert_3.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDyTCCArGgAwIBAgIUeoNdEiqhXVkpcYsmHaKiVS5W/tQwDQYJKoZIhvcNAQEL +BQAwPjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMREwDwYDVQQHDAhTYW4gSm9z +ZTEPMA0GA1UECgwGR29vZ2xlMB4XDTIwMDcxNjE2NTMxOVoXDTQwMDcxMTE2NTMx +OVowgZMxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTERMA8GA1UEBwwIU2FuIEpv +c2UxEjAQBgNVBAoMCUVuZCBQb2ludDEOMAwGA1UECwwFSW5mcmExIjAgBgkqhkiG +9w0BCQEWE2NpbmR5eHVlQGdvb2dsZS5jb20xHDAaBgNVBAMME2Zvby5iYXIuc2Vy +dmVyMy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDcIyJEt3ZA +xPn7H5f/IwXS8NcoAXWP8L6rWndcg+EWayx7W+wmUsFKGSFGzrFPPCFmKO8MrQqp +8LSAxHAVtOC6Uw+INWJJw9BRlx2nvV7hfbqu3OnPkPVkN/siUQCqnEKJQHliNT9X +Dl4/Mav75uQSWb3Vfi3KtG7mzPFNNbbe4yfHyGbC4e9RtKkGimDSJ413s3m4+scD +vtpCcCXj9XXZNdCwD1CL3kNdmOdhgfkDBP+AMLBFKZKqpCo6m0s4JJTiej13dc27 +wTrnkFm1CP77SV+kQlWg5DAcVXYJkN9FqNqExqIPS/SxMk7H+3qSQACbttQK9UmC +n3qR3pGbwqzNAgMBAAGjaTBnMB8GA1UdIwQYMBaAFG4bi8k0dOd7jSpPQQ6YUDAU +ARaxMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgTwMCwGA1UdEQQlMCOCCmdvb2dsZS5j +b22CCWFwcGxlLmNvbYIKYW1hem9uLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAn5aW +HEHNTDmcgC25oEtCj+IkoAslgFze4ZqkSz0HCzx76vj3AfMmIEvqB0W74wKqeZgm +V0D7I0xHkM3ILH4RjoCotpol3nLooIPFflA6Z1ILTRZl8mE5kfBSHzKdPS0egOf6 +kgrNYgJjBEtGNsmq8RKxAHVVAPgH88di0JnQDN5LcV9ZBKTQM2R7EM6a8eWD/Jsi +uujbNtdNERssSBV+Oil93MbsEcOT1RSKKxAiVvkHkR+45GRB889xBnqelcDVqcMK +Vcdp6X7aD5/Bu/4fq9AZlcHSEQDixNtjp/pQR0B5FsCGrb5OAz0B2t9jykDiIyj4 +4lxhQz8ykXf7ue0/ag== +-----END CERTIFICATE----- diff --git a/security/advancedtls/testdata/server_cert_3.txt b/security/advancedtls/testdata/server_cert_3.txt new file mode 100644 index 000000000000..e62c99cbf587 --- /dev/null +++ b/security/advancedtls/testdata/server_cert_3.txt @@ -0,0 +1,60 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 7a:83:5d:12:2a:a1:5d:59:29:71:8b:26:1d:a2:a2:55:2e:56:fe:d4 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, ST = CA, L = San Jose, O = Google + Validity + Not Before: Jul 16 16:53:19 2020 GMT + Not After : Jul 11 16:53:19 2040 GMT + Subject: C = US, ST = CA, L = San Jose, O = End Point, OU = Infra, emailAddress = cindyxue@google.com, CN = foo.bar.server3.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:dc:23:22:44:b7:76:40:c4:f9:fb:1f:97:ff:23: + 05:d2:f0:d7:28:01:75:8f:f0:be:ab:5a:77:5c:83: + e1:16:6b:2c:7b:5b:ec:26:52:c1:4a:19:21:46:ce: + b1:4f:3c:21:66:28:ef:0c:ad:0a:a9:f0:b4:80:c4: + 70:15:b4:e0:ba:53:0f:88:35:62:49:c3:d0:51:97: + 1d:a7:bd:5e:e1:7d:ba:ae:dc:e9:cf:90:f5:64:37: + fb:22:51:00:aa:9c:42:89:40:79:62:35:3f:57:0e: + 5e:3f:31:ab:fb:e6:e4:12:59:bd:d5:7e:2d:ca:b4: + 6e:e6:cc:f1:4d:35:b6:de:e3:27:c7:c8:66:c2:e1: + ef:51:b4:a9:06:8a:60:d2:27:8d:77:b3:79:b8:fa: + c7:03:be:da:42:70:25:e3:f5:75:d9:35:d0:b0:0f: + 50:8b:de:43:5d:98:e7:61:81:f9:03:04:ff:80:30: + b0:45:29:92:aa:a4:2a:3a:9b:4b:38:24:94:e2:7a: + 3d:77:75:cd:bb:c1:3a:e7:90:59:b5:08:fe:fb:49: + 5f:a4:42:55:a0:e4:30:1c:55:76:09:90:df:45:a8: + da:84:c6:a2:0f:4b:f4:b1:32:4e:c7:fb:7a:92:40: + 00:9b:b6:d4:0a:f5:49:82:9f:7a:91:de:91:9b:c2: + ac:cd + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:6E:1B:8B:C9:34:74:E7:7B:8D:2A:4F:41:0E:98:50:30:14:01:16:B1 + + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment + X509v3 Subject Alternative Name: + DNS:google.com, DNS:apple.com, DNS:amazon.com + Signature Algorithm: sha256WithRSAEncryption + 9f:96:96:1c:41:cd:4c:39:9c:80:2d:b9:a0:4b:42:8f:e2:24: + a0:0b:25:80:5c:de:e1:9a:a4:4b:3d:07:0b:3c:7b:ea:f8:f7: + 01:f3:26:20:4b:ea:07:45:bb:e3:02:aa:79:98:26:57:40:fb: + 23:4c:47:90:cd:c8:2c:7e:11:8e:80:a8:b6:9a:25:de:72:e8: + a0:83:c5:7e:50:3a:67:52:0b:4d:16:65:f2:61:39:91:f0:52: + 1f:32:9d:3d:2d:1e:80:e7:fa:92:0a:cd:62:02:63:04:4b:46: + 36:c9:aa:f1:12:b1:00:75:55:00:f8:07:f3:c7:62:d0:99:d0: + 0c:de:4b:71:5f:59:04:a4:d0:33:64:7b:10:ce:9a:f1:e5:83: + fc:9b:22:ba:e8:db:36:d7:4d:11:1b:2c:48:15:7e:3a:29:7d: + dc:c6:ec:11:c3:93:d5:14:8a:2b:10:22:56:f9:07:91:1f:b8: + e4:64:41:f3:cf:71:06:7a:9e:95:c0:d5:a9:c3:0a:55:c7:69: + e9:7e:da:0f:9f:c1:bb:fe:1f:ab:d0:19:95:c1:d2:11:00:e2: + c4:db:63:a7:fa:50:47:40:79:16:c0:86:ad:be:4e:03:3d:01: + da:df:63:ca:40:e2:23:28:f8:e2:5c:61:43:3f:32:91:77:fb: + b9:ed:3f:6a diff --git a/security/advancedtls/testdata/server_key_3.pem b/security/advancedtls/testdata/server_key_3.pem new file mode 100644 index 000000000000..ae8ff1a75b4d --- /dev/null +++ b/security/advancedtls/testdata/server_key_3.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDcIyJEt3ZAxPn7 +H5f/IwXS8NcoAXWP8L6rWndcg+EWayx7W+wmUsFKGSFGzrFPPCFmKO8MrQqp8LSA +xHAVtOC6Uw+INWJJw9BRlx2nvV7hfbqu3OnPkPVkN/siUQCqnEKJQHliNT9XDl4/ +Mav75uQSWb3Vfi3KtG7mzPFNNbbe4yfHyGbC4e9RtKkGimDSJ413s3m4+scDvtpC +cCXj9XXZNdCwD1CL3kNdmOdhgfkDBP+AMLBFKZKqpCo6m0s4JJTiej13dc27wTrn +kFm1CP77SV+kQlWg5DAcVXYJkN9FqNqExqIPS/SxMk7H+3qSQACbttQK9UmCn3qR +3pGbwqzNAgMBAAECggEAU0Te84tKKdnYjUs4HYRL8ay0VienJpl0JjEEMXSZMfe8 +TbVJsH1hK/wxgC0zGLuwDoqxUeQqwnmQbZzgoPVYhGJi360BztFI/XPh/c8+EqGS +eg6KSr+UcyJR1ns5e0+8Q1qmD6YAnZeLwu+xFIoT/3T+v8EI5UI3KQqgxAnrcIdc +RWqIwWLkkPm1QVRYsvRaTvmgFd2LcIT9AdIruP/VsqF3GEzvEQSr0lgmwOe0izLb +HKfZr+2JwOppwTLGhKo1wUyUUsglXCBOcFYAA03xdviQWBuCeKXamNrdB7M0T4zZ +THheNRQq2g7bTYnncCYKcrNa5VY5wmHY767mf6ahAQKBgQD+AGk21CsRgiKCGzUI +wTRynutAMkX55U1bud2+OMpzH9omvnccX5ezq5WTw/jZfz+jrUBF8YKSTtb3InUg +yXcpJ/XjRDFMZp1Avy/44rOlYg1QYMD4JK96f8bbd1yej5NVw45V9synaJHuvoDV +bkbZu00S0X8Pgvlh354MUH3CLQKBgQDd3oQdKMZgsX8gtmcQfQoEZ0VvlOYmTM5W +Kw+24iGrBkfBt+NuKx8qm1CpoFGx4G2+TgttMywjF9RG3R2uGqbJZbCOAXzjRMQJ +L9PuTiGAdYD3fA5cTmnrrNEhPydtRhF2M3p8FFeQtwsEBYreXux25rbmVOYTFMgJ +hVUW9RdZIQKBgQDwEYdgMQw70hm3iuuHSMS/iQCkfl+xH08MYRH6FkcSpIpVkDOX +96m0QXpwXQs41pJZqwhSkz9r9WQr1L+Lq58aoRBAK1XE9j+u0IUQ4YQVziTzUV9R +qarJRze2eoxpuR3yM5C2IzuvBqDXW+r8zuvcIrFoFeXXzVzTar1AulsCSQKBgQCa +UD+3QDrp2co/6F26vB0RfvpuZzPEA7undv/RBWrBVvblp46Je3iL28a4lAb+Hsh1 +ijasVuEl71b3iqcwBt1mSlIIEsTYFWX7tcZDgxgODqwKdcBPN0K4ZlR2OUSk3g0b +Fybj0gotXwJMY8Z4b7Er6b/gZ8A2GUggRxotg34fwQKBgEh6a88SgTyu1KcR2yzN +Zbs8MEfZ8hqfUj+GL0+6y9KQd4uSIngyHWGNETE9dCObNz5HEdJIpUNvB3vfN0Vk +f1EEPDQLQKJjii7jZ9U9XfPVaUhqIVH3Aupmb30H3AQw7XOF23g63k9Yg1FWtDT6 +4CuBsUvjXywL4yHrWK+BuSXF +-----END PRIVATE KEY----- diff --git a/xds/internal/client/bootstrap/bootstrap.go b/xds/internal/client/bootstrap/bootstrap.go index 1e2e05e8f9b2..b2805bf73720 100644 --- a/xds/internal/client/bootstrap/bootstrap.go +++ b/xds/internal/client/bootstrap/bootstrap.go @@ -195,6 +195,10 @@ func NewConfig() (*Config, error) { // 2. Environment variable "GRPC_XDS_EXPERIMENTAL_V3_SUPPORT" is set to // true. // The default value of the enum type "version.TransportAPI" is v2. + // + // TODO: there are multiple env variables, GRPC_XDS_BOOTSTRAP and + // GRPC_XDS_EXPERIMENTAL_V3_SUPPORT. Move all env variables into a separate + // package. if v3Env := os.Getenv(v3SupportEnv); v3Env == "true" { if serverSupportsV3 { config.TransportAPI = version.TransportV3 diff --git a/xds/internal/client/client_watchers_rds.go b/xds/internal/client/client_watchers_rds.go index 91de78601b49..cc1b18c2d915 100644 --- a/xds/internal/client/client_watchers_rds.go +++ b/xds/internal/client/client_watchers_rds.go @@ -49,10 +49,6 @@ type Route struct { } type rdsUpdate struct { - // weightedCluster is only set when routing is disabled (env variable - // GRPC_XDS_EXPERIMENTAL_ROUTING is not true). - weightedCluster map[string]uint32 - routes []*Route } type rdsCallbackFunc func(rdsUpdate, error) diff --git a/xds/internal/client/client_watchers_rds_test.go b/xds/internal/client/client_watchers_rds_test.go index 06ed7a377e2b..16e042ecd961 100644 --- a/xds/internal/client/client_watchers_rds_test.go +++ b/xds/internal/client/client_watchers_rds_test.go @@ -54,7 +54,7 @@ func (s) TestRDSWatch(t *testing.T) { t.Fatalf("want new watch to start, got error %v", err) } - wantUpdate := rdsUpdate{weightedCluster: map[string]uint32{testCDSName: 1}} + wantUpdate := rdsUpdate{routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName: 1}}}} v2Client.r.newRDSUpdate(map[string]rdsUpdate{ testRDSName: wantUpdate, }) @@ -113,7 +113,7 @@ func (s) TestRDSTwoWatchSameResourceName(t *testing.T) { } } - wantUpdate := rdsUpdate{weightedCluster: map[string]uint32{testCDSName: 1}} + wantUpdate := rdsUpdate{routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName: 1}}}} v2Client.r.newRDSUpdate(map[string]rdsUpdate{ testRDSName: wantUpdate, }) @@ -179,8 +179,8 @@ func (s) TestRDSThreeWatchDifferentResourceName(t *testing.T) { t.Fatalf("want new watch to start, got error %v", err) } - wantUpdate1 := rdsUpdate{weightedCluster: map[string]uint32{testCDSName + "1": 1}} - wantUpdate2 := rdsUpdate{weightedCluster: map[string]uint32{testCDSName + "2": 1}} + wantUpdate1 := rdsUpdate{routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName + "1": 1}}}} + wantUpdate2 := rdsUpdate{routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName + "2": 1}}}} v2Client.r.newRDSUpdate(map[string]rdsUpdate{ testRDSName + "1": wantUpdate1, testRDSName + "2": wantUpdate2, @@ -219,7 +219,7 @@ func (s) TestRDSWatchAfterCache(t *testing.T) { t.Fatalf("want new watch to start, got error %v", err) } - wantUpdate := rdsUpdate{weightedCluster: map[string]uint32{testCDSName: 1}} + wantUpdate := rdsUpdate{routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName: 1}}}} v2Client.r.newRDSUpdate(map[string]rdsUpdate{ testRDSName: wantUpdate, }) diff --git a/xds/internal/client/client_watchers_service.go b/xds/internal/client/client_watchers_service.go index 1cf4c0f988c1..cc96622d71d3 100644 --- a/xds/internal/client/client_watchers_service.go +++ b/xds/internal/client/client_watchers_service.go @@ -25,14 +25,7 @@ import ( // ServiceUpdate contains update about the service. type ServiceUpdate struct { - // WeightedCluster is a map from cluster names (CDS resource to watch) to - // their weights. - // - // This field is only set when routing is disabled (env variable - // GRPC_XDS_EXPERIMENTAL_ROUTING is not true). - WeightedCluster map[string]uint32 - - // Routes + // Routes contain matchers+actions to route RPCs. Routes []*Route } @@ -126,8 +119,7 @@ func (w *serviceUpdateWatcher) handleRDSResp(update rdsUpdate, err error) { return } w.serviceCb(ServiceUpdate{ - WeightedCluster: update.weightedCluster, - Routes: update.routes, + Routes: update.routes, }, nil) } diff --git a/xds/internal/client/client_watchers_service_test.go b/xds/internal/client/client_watchers_service_test.go index 4535285bd6b4..4b72f63e8ee6 100644 --- a/xds/internal/client/client_watchers_service_test.go +++ b/xds/internal/client/client_watchers_service_test.go @@ -58,7 +58,7 @@ func (s) TestServiceWatch(t *testing.T) { serviceUpdateCh.Send(serviceUpdateErr{u: update, err: err}) }) - wantUpdate := ServiceUpdate{WeightedCluster: map[string]uint32{testCDSName: 1}} + wantUpdate := ServiceUpdate{Routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName: 1}}}} if _, err := v2Client.addWatches[ldsURL].Receive(); err != nil { t.Fatalf("want new watch to start, got error %v", err) @@ -70,7 +70,7 @@ func (s) TestServiceWatch(t *testing.T) { t.Fatalf("want new watch to start, got error %v", err) } v2Client.r.newRDSUpdate(map[string]rdsUpdate{ - testRDSName: {weightedCluster: map[string]uint32{testCDSName: 1}}, + testRDSName: {routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName: 1}}}}, }) if u, err := serviceUpdateCh.Receive(); err != nil || !cmp.Equal(u, serviceUpdateErr{wantUpdate, nil}, serviceCmpOpts...) { @@ -116,7 +116,7 @@ func (s) TestServiceWatchLDSUpdate(t *testing.T) { serviceUpdateCh.Send(serviceUpdateErr{u: update, err: err}) }) - wantUpdate := ServiceUpdate{WeightedCluster: map[string]uint32{testCDSName: 1}} + wantUpdate := ServiceUpdate{Routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName: 1}}}} if _, err := v2Client.addWatches[ldsURL].Receive(); err != nil { t.Fatalf("want new watch to start, got error %v", err) @@ -128,7 +128,7 @@ func (s) TestServiceWatchLDSUpdate(t *testing.T) { t.Fatalf("want new watch to start, got error %v", err) } v2Client.r.newRDSUpdate(map[string]rdsUpdate{ - testRDSName: {weightedCluster: map[string]uint32{testCDSName: 1}}, + testRDSName: {routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName: 1}}}}, }) if u, err := serviceUpdateCh.Receive(); err != nil || !cmp.Equal(u, serviceUpdateErr{wantUpdate, nil}, serviceCmpOpts...) { @@ -145,17 +145,17 @@ func (s) TestServiceWatchLDSUpdate(t *testing.T) { // Another update for the old name. v2Client.r.newRDSUpdate(map[string]rdsUpdate{ - testRDSName: {weightedCluster: map[string]uint32{testCDSName: 1}}, + testRDSName: {routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName: 1}}}}, }) if u, err := serviceUpdateCh.Receive(); err != testutils.ErrRecvTimeout { t.Errorf("unexpected serviceUpdate: %v, %v, want channel recv timeout", u, err) } - wantUpdate2 := ServiceUpdate{WeightedCluster: map[string]uint32{testCDSName + "2": 1}} + wantUpdate2 := ServiceUpdate{Routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName + "2": 1}}}} // RDS update for the new name. v2Client.r.newRDSUpdate(map[string]rdsUpdate{ - testRDSName + "2": {weightedCluster: map[string]uint32{testCDSName + "2": 1}}, + testRDSName + "2": {routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName + "2": 1}}}}, }) if u, err := serviceUpdateCh.Receive(); err != nil || !cmp.Equal(u, serviceUpdateErr{wantUpdate2, nil}, serviceCmpOpts...) { @@ -183,7 +183,7 @@ func (s) TestServiceWatchSecond(t *testing.T) { serviceUpdateCh.Send(serviceUpdateErr{u: update, err: err}) }) - wantUpdate := ServiceUpdate{WeightedCluster: map[string]uint32{testCDSName: 1}} + wantUpdate := ServiceUpdate{Routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName: 1}}}} if _, err := v2Client.addWatches[ldsURL].Receive(); err != nil { t.Fatalf("want new watch to start, got error %v", err) @@ -195,7 +195,7 @@ func (s) TestServiceWatchSecond(t *testing.T) { t.Fatalf("want new watch to start, got error %v", err) } v2Client.r.newRDSUpdate(map[string]rdsUpdate{ - testRDSName: {weightedCluster: map[string]uint32{testCDSName: 1}}, + testRDSName: {routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName: 1}}}}, }) if u, err := serviceUpdateCh.Receive(); err != nil || !cmp.Equal(u, serviceUpdateErr{wantUpdate, nil}, serviceCmpOpts...) { @@ -226,7 +226,7 @@ func (s) TestServiceWatchSecond(t *testing.T) { testLDSName: {routeName: testRDSName}, }) v2Client.r.newRDSUpdate(map[string]rdsUpdate{ - testRDSName: {weightedCluster: map[string]uint32{testCDSName: 1}}, + testRDSName: {routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName: 1}}}}, }) if u, err := serviceUpdateCh.Receive(); err != nil || !cmp.Equal(u, serviceUpdateErr{wantUpdate, nil}, serviceCmpOpts...) { @@ -263,8 +263,8 @@ func (s) TestServiceWatchWithNoResponseFromServer(t *testing.T) { callbackCh := testutils.NewChannel() cancelWatch := xdsClient.WatchService(goodLDSTarget1, func(su ServiceUpdate, err error) { - if su.WeightedCluster != nil { - callbackCh.Send(fmt.Errorf("got WeightedCluster: %+v, want nil", su.WeightedCluster)) + if su.Routes != nil { + callbackCh.Send(fmt.Errorf("got WeightedCluster: %+v, want nil", su.Routes)) return } if err == nil { @@ -307,8 +307,8 @@ func (s) TestServiceWatchEmptyRDS(t *testing.T) { callbackCh := testutils.NewChannel() cancelWatch := xdsClient.WatchService(goodLDSTarget1, func(su ServiceUpdate, err error) { - if su.WeightedCluster != nil { - callbackCh.Send(fmt.Errorf("got WeightedCluster: %+v, want nil", su.WeightedCluster)) + if su.Routes != nil { + callbackCh.Send(fmt.Errorf("got WeightedCluster: %+v, want nil", su.Routes)) return } if err == nil { @@ -394,7 +394,7 @@ func (s) TestServiceNotCancelRDSOnSameLDSUpdate(t *testing.T) { serviceUpdateCh.Send(serviceUpdateErr{u: update, err: err}) }) - wantUpdate := ServiceUpdate{WeightedCluster: map[string]uint32{testCDSName: 1}} + wantUpdate := ServiceUpdate{Routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName: 1}}}} if _, err := v2Client.addWatches[ldsURL].Receive(); err != nil { t.Fatalf("want new watch to start, got error %v", err) @@ -406,7 +406,7 @@ func (s) TestServiceNotCancelRDSOnSameLDSUpdate(t *testing.T) { t.Fatalf("want new watch to start, got error %v", err) } v2Client.r.newRDSUpdate(map[string]rdsUpdate{ - testRDSName: {weightedCluster: map[string]uint32{testCDSName: 1}}, + testRDSName: {routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName: 1}}}}, }) if u, err := serviceUpdateCh.Receive(); err != nil || !cmp.Equal(u, serviceUpdateErr{wantUpdate, nil}, serviceCmpOpts...) { @@ -445,7 +445,7 @@ func (s) TestServiceResourceRemoved(t *testing.T) { serviceUpdateCh.Send(serviceUpdateErr{u: update, err: err}) }) - wantUpdate := ServiceUpdate{WeightedCluster: map[string]uint32{testCDSName: 1}} + wantUpdate := ServiceUpdate{Routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName: 1}}}} if _, err := v2Client.addWatches[ldsURL].Receive(); err != nil { t.Fatalf("want new watch to start, got error %v", err) @@ -457,7 +457,7 @@ func (s) TestServiceResourceRemoved(t *testing.T) { t.Fatalf("want new watch to start, got error %v", err) } v2Client.r.newRDSUpdate(map[string]rdsUpdate{ - testRDSName: {weightedCluster: map[string]uint32{testCDSName: 1}}, + testRDSName: {routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName: 1}}}}, }) if u, err := serviceUpdateCh.Receive(); err != nil || !cmp.Equal(u, serviceUpdateErr{wantUpdate, nil}, serviceCmpOpts...) { @@ -477,7 +477,7 @@ func (s) TestServiceResourceRemoved(t *testing.T) { // Send RDS update for the removed LDS resource, expect no updates to // callback, because RDS should be canceled. v2Client.r.newRDSUpdate(map[string]rdsUpdate{ - testRDSName: {weightedCluster: map[string]uint32{testCDSName + "new": 1}}, + testRDSName: {routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName + "new": 1}}}}, }) if u, err := serviceUpdateCh.Receive(); err != testutils.ErrRecvTimeout { t.Errorf("unexpected serviceUpdate: %v, want receiving from channel timeout", u) @@ -497,9 +497,9 @@ func (s) TestServiceResourceRemoved(t *testing.T) { } v2Client.r.newRDSUpdate(map[string]rdsUpdate{ - testRDSName: {weightedCluster: map[string]uint32{testCDSName + "new2": 1}}, + testRDSName: {routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName + "new2": 1}}}}, }) - if u, err := serviceUpdateCh.Receive(); err != nil || !cmp.Equal(u, serviceUpdateErr{ServiceUpdate{WeightedCluster: map[string]uint32{testCDSName + "new2": 1}}, nil}, serviceCmpOpts...) { + if u, err := serviceUpdateCh.Receive(); err != nil || !cmp.Equal(u, serviceUpdateErr{ServiceUpdate{Routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{testCDSName + "new2": 1}}}}, nil}, serviceCmpOpts...) { t.Errorf("unexpected serviceUpdate: %v, error receiving from channel: %v", u, err) } } diff --git a/xds/internal/client/v2client_rds.go b/xds/internal/client/v2client_rds.go index 1fc9ac9752bf..cc71f6538f62 100644 --- a/xds/internal/client/v2client_rds.go +++ b/xds/internal/client/v2client_rds.go @@ -97,51 +97,11 @@ func generateRDSUpdateFromRouteConfiguration(rc *xdspb.RouteConfiguration, host return rdsUpdate{}, fmt.Errorf("matched virtual host has no routes") } - // Keep the old code path for routing disabled. - if routingEnabled { - routes, err := routesProtoToSlice(vh.Routes, logger) - if err != nil { - return rdsUpdate{}, fmt.Errorf("received route is invalid: %v", err) - } - return rdsUpdate{routes: routes}, nil - } - - dr := vh.Routes[len(vh.Routes)-1] - match := dr.GetMatch() - if match == nil { - return rdsUpdate{}, fmt.Errorf("matched virtual host's default route doesn't have a match") - } - if prefix := match.GetPrefix(); prefix != "" && prefix != "/" { - // The matched virtual host is invalid. Match is not "" or "/". - return rdsUpdate{}, fmt.Errorf("matched virtual host's default route is %v, want Prefix empty string or /", match) - } - if caseSensitive := match.GetCaseSensitive(); caseSensitive != nil && !caseSensitive.Value { - // The case sensitive is set to false. Not set or set to true are both - // valid. - return rdsUpdate{}, fmt.Errorf("matched virtual host's default route set case-sensitive to false") - } - routeAction := dr.GetRoute() - if routeAction == nil { - return rdsUpdate{}, fmt.Errorf("matched route is nil") + routes, err := routesProtoToSlice(vh.Routes, logger) + if err != nil { + return rdsUpdate{}, fmt.Errorf("received route is invalid: %v", err) } - - if wc := routeAction.GetWeightedClusters(); wc != nil { - m, err := weightedClustersProtoToMap(wc) - if err != nil { - return rdsUpdate{}, fmt.Errorf("matched weighted cluster is invalid: %v", err) - } - return rdsUpdate{weightedCluster: m}, nil - } - - // When there's just one cluster, we set weightedCluster to map with one - // entry. This mean we will build a weighted_target balancer even if there's - // just one cluster. - // - // Otherwise, we will need to switch the top policy between weighted_target - // and CDS. In case when the action changes between one cluster and multiple - // clusters, changing top level policy means recreating TCP connection every - // time. - return rdsUpdate{weightedCluster: map[string]uint32{routeAction.GetCluster(): 1}}, nil + return rdsUpdate{routes: routes}, nil } func routesProtoToSlice(routes []*routepb.Route, logger *grpclog.PrefixLogger) ([]*Route, error) { diff --git a/xds/internal/client/v2client_rds_test.go b/xds/internal/client/v2client_rds_test.go index e3ec4e01fd8f..3e5ef96fd6ba 100644 --- a/xds/internal/client/v2client_rds_test.go +++ b/xds/internal/client/v2client_rds_test.go @@ -158,7 +158,7 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) { { name: "good-route-config-with-empty-string-route", rc: goodRouteConfig1, - wantUpdate: rdsUpdate{weightedCluster: map[string]uint32{goodClusterName1: 1}}, + wantUpdate: rdsUpdate{routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{goodClusterName1: 1}}}}, }, { // default route's match is not empty string, but "/". @@ -173,7 +173,7 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) { Route: &routepb.RouteAction{ ClusterSpecifier: &routepb.RouteAction_Cluster{Cluster: goodClusterName1}, }}}}}}}, - wantUpdate: rdsUpdate{weightedCluster: map[string]uint32{goodClusterName1: 1}}, + wantUpdate: rdsUpdate{routes: []*Route{{Prefix: newStringP("/"), Action: map[string]uint32{goodClusterName1: 1}}}}, }, { @@ -217,7 +217,7 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) { }, TotalWeight: &wrapperspb.UInt32Value{Value: 10}, }}}}}}}}}, - wantUpdate: rdsUpdate{weightedCluster: map[string]uint32{"a": 2, "b": 3, "c": 5}}, + wantUpdate: rdsUpdate{routes: []*Route{{Prefix: newStringP("/"), Action: map[string]uint32{"a": 2, "b": 3, "c": 5}}}}, }, } @@ -243,59 +243,10 @@ func doLDS(t *testing.T, v2c *v2Client, fakeServer *fakeserver.Server) { } } -// TestRDSHandleResponseWithRoutingEnabled starts a fake xDS server, makes a -// ClientConn to it, and creates a v2Client using it. Then, it registers an LDS -// and RDS watcher and tests different RDS responses. -// -// Routing is protected by an env variable. This test sets it to true, so the -// new fields will be parsed. -func (s) TestRDSHandleResponseWithRoutingEnabled(t *testing.T) { - routingEnabled = true - defer func() { - routingEnabled = false - }() - tests := []struct { - name string - rdsResponse *xdspb.DiscoveryResponse - wantErr bool - wantUpdate *rdsUpdate - wantUpdateErr bool - }{ - // Response contains one good interesting RouteConfiguration. - { - name: "one-good-route-config", - rdsResponse: goodRDSResponse1, - wantErr: false, - wantUpdate: &rdsUpdate{ - // Instead of just weighted targets when routing is disabled, - // this result contains a route with perfix "", and action as - // weighted targets. - routes: []*Route{{ - Prefix: newStringP(""), - Action: map[string]uint32{goodClusterName1: 1}, - }}, - }, - wantUpdateErr: false, - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - testWatchHandle(t, &watchHandleTestcase{ - typeURL: rdsURL, - resourceName: goodRouteName1, - responseToHandle: test.rdsResponse, - wantHandleErr: test.wantErr, - wantUpdate: test.wantUpdate, - wantUpdateErr: test.wantUpdateErr, - }) - }) - } -} - -// TestRDSHandleResponseWithRoutingDisabled starts a fake xDS server, makes a -// ClientConn to it, and creates a v2Client using it. Then, it registers an LDS -// and RDS watcher and tests different RDS responses. -func (s) TestRDSHandleResponseWithRoutingDisabled(t *testing.T) { +// TestRDSHandleResponseWithRouting starts a fake xDS server, makes a ClientConn +// to it, and creates a v2Client using it. Then, it registers an LDS and RDS +// watcher and tests different RDS responses. +func (s) TestRDSHandleResponseWithRouting(t *testing.T) { tests := []struct { name string rdsResponse *xdspb.DiscoveryResponse @@ -342,7 +293,22 @@ func (s) TestRDSHandleResponseWithRoutingDisabled(t *testing.T) { name: "one-good-route-config", rdsResponse: goodRDSResponse1, wantErr: false, - wantUpdate: &rdsUpdate{weightedCluster: map[string]uint32{goodClusterName1: 1}}, + wantUpdate: &rdsUpdate{routes: []*Route{{Prefix: newStringP(""), Action: map[string]uint32{goodClusterName1: 1}}}}, + wantUpdateErr: false, + }, + { + name: "one-good-route-config with routes", + rdsResponse: goodRDSResponse1, + wantErr: false, + wantUpdate: &rdsUpdate{ + // Instead of just weighted targets when routing is disabled, + // this result contains a route with perfix "", and action as + // weighted targets. + routes: []*Route{{ + Prefix: newStringP(""), + Action: map[string]uint32{goodClusterName1: 1}, + }}, + }, wantUpdateErr: false, }, } diff --git a/xds/internal/resolver/serviceconfig.go b/xds/internal/resolver/serviceconfig.go index 84c5753adf61..805d8d41104c 100644 --- a/xds/internal/resolver/serviceconfig.go +++ b/xds/internal/resolver/serviceconfig.go @@ -137,23 +137,6 @@ func weightedClusterToBalancerConfig(wc map[string]uint32) balancerConfig { return bc } -func weightedClusterToJSON(wc map[string]uint32) (string, error) { - sc := serviceConfig{ - LoadBalancingConfig: weightedClusterToBalancerConfig(wc), - } - bs, err := json.Marshal(sc) - if err != nil { - return "", fmt.Errorf("failed to marshal json: %v", err) - } - return string(bs), nil -} - func (r *xdsResolver) serviceUpdateToJSON(su xdsclient.ServiceUpdate) (string, error) { - // If WeightedClusters is set, routing is disabled (by env variable). Use - // weighted target only. - if su.WeightedCluster != nil { - return weightedClusterToJSON(su.WeightedCluster) - } - return r.routesToJSON(su.Routes) } diff --git a/xds/internal/resolver/serviceconfig_test.go b/xds/internal/resolver/serviceconfig_test.go index 4e149893ee70..ce4a7e8fab9c 100644 --- a/xds/internal/resolver/serviceconfig_test.go +++ b/xds/internal/resolver/serviceconfig_test.go @@ -32,31 +32,44 @@ import ( ) const ( - testCluster1 = "test-cluster-1" - testClusterOnlyJSON = `{"loadBalancingConfig":[{ - "weighted_target_experimental": { - "targets": { "test-cluster-1" : { "weight":1, "childPolicy":[{"cds_experimental":{"cluster":"test-cluster-1"}}] } } - } - }]}` + testCluster1 = "test-cluster-1" + testOneClusterOnlyJSON = `{"loadBalancingConfig":[{ + "xds_routing_experimental":{ + "action":{ + "test-cluster-1_0":{ + "childPolicy":[{ + "weighted_target_experimental":{ + "targets":{ + "test-cluster-1":{ + "weight":1, + "childPolicy":[{"cds_experimental":{"cluster":"test-cluster-1"}}] + } + }}}] + } + }, + "route":[{"prefix":"","action":"test-cluster-1_0"}] + }}]}` testWeightedCDSJSON = `{"loadBalancingConfig":[{ - "weighted_target_experimental": { - "targets": { - "cluster_1" : { - "weight":75, - "childPolicy":[{"cds_experimental":{"cluster":"cluster_1"}}] - }, - "cluster_2" : { - "weight":25, - "childPolicy":[{"cds_experimental":{"cluster":"cluster_2"}}] - } - } - } - }]}` - testWeightedCDSNoChildJSON = `{"loadBalancingConfig":[{ - "weighted_target_experimental": { - "targets": {} - } - }]}` + "xds_routing_experimental":{ + "action":{ + "cluster_1_cluster_2_1":{ + "childPolicy":[{ + "weighted_target_experimental":{ + "targets":{ + "cluster_1":{ + "weight":75, + "childPolicy":[{"cds_experimental":{"cluster":"cluster_1"}}] + }, + "cluster_2":{ + "weight":25, + "childPolicy":[{"cds_experimental":{"cluster":"cluster_2"}}] + } + }}}] + } + }, + "route":[{"prefix":"","action":"cluster_1_cluster_2_1"}] + }}]}` + testRoutingJSON = `{"loadBalancingConfig":[{ "xds_routing_experimental": { "action":{ @@ -178,51 +191,6 @@ const ( ` ) -func TestWeightedClusterToJSON(t *testing.T) { - tests := []struct { - name string - wc map[string]uint32 - wantJSON string // wantJSON is not to be compared verbatim. - }{ - { - name: "one cluster only", - wc: map[string]uint32{testCluster1: 1}, - wantJSON: testClusterOnlyJSON, - }, - { - name: "empty weighted clusters", - wc: nil, - wantJSON: testWeightedCDSNoChildJSON, - }, - { - name: "weighted clusters", - wc: map[string]uint32{ - "cluster_1": 75, - "cluster_2": 25, - }, - wantJSON: testWeightedCDSJSON, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotJSON, err := weightedClusterToJSON(tt.wc) - if err != nil { - t.Errorf("serviceUpdateToJSON returned error: %v", err) - return - } - - gotParsed := internal.ParseServiceConfigForTesting.(func(string) *serviceconfig.ParseResult)(gotJSON) - wantParsed := internal.ParseServiceConfigForTesting.(func(string) *serviceconfig.ParseResult)(tt.wantJSON) - - if !internal.EqualServiceConfigForTesting(gotParsed.Config, wantParsed.Config) { - t.Errorf("serviceUpdateToJSON() = %v, want %v", gotJSON, tt.wantJSON) - t.Error("gotParsed: ", cmp.Diff(nil, gotParsed)) - t.Error("wantParsed: ", cmp.Diff(nil, wantParsed)) - } - }) - } -} - func TestRoutesToJSON(t *testing.T) { tests := []struct { name string @@ -348,15 +316,6 @@ func TestServiceUpdateToJSON(t *testing.T) { wantJSON string wantErr bool }{ - { - name: "weighted clusters", - su: client.ServiceUpdate{WeightedCluster: map[string]uint32{ - "cluster_1": 75, - "cluster_2": 25, - }}, - wantJSON: testWeightedCDSJSON, - wantErr: false, - }, { name: "routing", su: client.ServiceUpdate{ diff --git a/xds/internal/resolver/xds_resolver_test.go b/xds/internal/resolver/xds_resolver_test.go index d84ec44eb8c0..5c3b0fce84e1 100644 --- a/xds/internal/resolver/xds_resolver_test.go +++ b/xds/internal/resolver/xds_resolver_test.go @@ -272,7 +272,7 @@ func TestXDSResolverWatchCallbackAfterClose(t *testing.T) { // Call the watchAPI callback after closing the resolver, and make sure no // update is triggerred on the ClientConn. xdsR.Close() - xdsC.InvokeWatchServiceCallback(xdsclient.ServiceUpdate{WeightedCluster: map[string]uint32{cluster: 1}}, nil) + xdsC.InvokeWatchServiceCallback(xdsclient.ServiceUpdate{Routes: []*client.Route{{Prefix: newStringP(""), Action: map[string]uint32{cluster: 1}}}}, nil) if gotVal, gotErr := tcc.stateCh.Receive(); gotErr != testutils.ErrRecvTimeout { t.Fatalf("ClientConn.UpdateState called after xdsResolver is closed: %v", gotVal) } @@ -316,20 +316,21 @@ func TestXDSResolverGoodServiceUpdate(t *testing.T) { }() waitForWatchService(t, xdsC, targetStr) + defer replaceRandNumGenerator(0)() for _, tt := range []struct { su client.ServiceUpdate wantJSON string }{ { - su: client.ServiceUpdate{WeightedCluster: map[string]uint32{testCluster1: 1}}, - wantJSON: testClusterOnlyJSON, + su: client.ServiceUpdate{Routes: []*client.Route{{Prefix: newStringP(""), Action: map[string]uint32{testCluster1: 1}}}}, + wantJSON: testOneClusterOnlyJSON, }, { - su: client.ServiceUpdate{WeightedCluster: map[string]uint32{ + su: client.ServiceUpdate{Routes: []*client.Route{{Prefix: newStringP(""), Action: map[string]uint32{ "cluster_1": 75, "cluster_2": 25, - }}, + }}}}, wantJSON: testWeightedCDSJSON, }, } { @@ -382,7 +383,7 @@ func TestXDSResolverGoodUpdateAfterError(t *testing.T) { // Invoke the watchAPI callback with a good service update and wait for the // UpdateState method to be called on the ClientConn. - xdsC.InvokeWatchServiceCallback(xdsclient.ServiceUpdate{WeightedCluster: map[string]uint32{cluster: 1}}, nil) + xdsC.InvokeWatchServiceCallback(xdsclient.ServiceUpdate{Routes: []*client.Route{{Prefix: newStringP(""), Action: map[string]uint32{cluster: 1}}}}, nil) gotState, err := tcc.stateCh.Receive() if err != nil { t.Fatalf("ClientConn.UpdateState returned error: %v", err)