1/*
2 *
3 * Copyright 2014 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19// Binary client is an interop client.
20package main
21
22import (
23	"crypto/tls"
24	"crypto/x509"
25	"flag"
26	"io/ioutil"
27	"net"
28	"strconv"
29
30	"google.golang.org/grpc"
31	_ "google.golang.org/grpc/balancer/grpclb"
32	"google.golang.org/grpc/credentials"
33	"google.golang.org/grpc/credentials/alts"
34	"google.golang.org/grpc/credentials/google"
35	"google.golang.org/grpc/credentials/oauth"
36	"google.golang.org/grpc/grpclog"
37	"google.golang.org/grpc/interop"
38	"google.golang.org/grpc/resolver"
39	"google.golang.org/grpc/testdata"
40	_ "google.golang.org/grpc/xds/googledirectpath"
41
42	testgrpc "google.golang.org/grpc/interop/grpc_testing"
43)
44
45const (
46	googleDefaultCredsName = "google_default_credentials"
47	computeEngineCredsName = "compute_engine_channel_creds"
48)
49
50var (
51	caFile                = flag.String("ca_file", "", "The file containning the CA root cert file")
52	useTLS                = flag.Bool("use_tls", false, "Connection uses TLS if true")
53	useALTS               = flag.Bool("use_alts", false, "Connection uses ALTS if true (this option can only be used on GCP)")
54	customCredentialsType = flag.String("custom_credentials_type", "", "Custom creds to use, excluding TLS or ALTS")
55	altsHSAddr            = flag.String("alts_handshaker_service_address", "", "ALTS handshaker gRPC service address")
56	testCA                = flag.Bool("use_test_ca", false, "Whether to replace platform root CAs with test CA as the CA root")
57	serviceAccountKeyFile = flag.String("service_account_key_file", "", "Path to service account json key file")
58	oauthScope            = flag.String("oauth_scope", "", "The scope for OAuth2 tokens")
59	defaultServiceAccount = flag.String("default_service_account", "", "Email of GCE default service account")
60	serverHost            = flag.String("server_host", "localhost", "The server host name")
61	serverPort            = flag.Int("server_port", 10000, "The server port number")
62	serviceConfigJSON     = flag.String("service_config_json", "", "Disables service config lookups and sets the provided string as the default service config.")
63	tlsServerName         = flag.String("server_host_override", "", "The server name used to verify the hostname returned by TLS handshake if it is not empty. Otherwise, --server_host is used.")
64	testCase              = flag.String("test_case", "large_unary",
65		`Configure different test cases. Valid options are:
66        empty_unary : empty (zero bytes) request and response;
67        large_unary : single request and (large) response;
68        client_streaming : request streaming with single response;
69        server_streaming : single request with response streaming;
70        ping_pong : full-duplex streaming;
71        empty_stream : full-duplex streaming with zero message;
72        timeout_on_sleeping_server: fullduplex streaming on a sleeping server;
73        compute_engine_creds: large_unary with compute engine auth;
74        service_account_creds: large_unary with service account auth;
75        jwt_token_creds: large_unary with jwt token auth;
76        per_rpc_creds: large_unary with per rpc token;
77        oauth2_auth_token: large_unary with oauth2 token auth;
78        google_default_credentials: large_unary with google default credentials
79        compute_engine_channel_credentials: large_unary with compute engine creds
80        cancel_after_begin: cancellation after metadata has been sent but before payloads are sent;
81        cancel_after_first_response: cancellation after receiving 1st message from the server;
82        status_code_and_message: status code propagated back to client;
83        special_status_message: Unicode and whitespace is correctly processed in status message;
84        custom_metadata: server will echo custom metadata;
85        unimplemented_method: client attempts to call unimplemented method;
86        unimplemented_service: client attempts to call unimplemented service;
87        pick_first_unary: all requests are sent to one server despite multiple servers are resolved.`)
88
89	logger = grpclog.Component("interop")
90)
91
92type credsMode uint8
93
94const (
95	credsNone credsMode = iota
96	credsTLS
97	credsALTS
98	credsGoogleDefaultCreds
99	credsComputeEngineCreds
100)
101
102func main() {
103	flag.Parse()
104	var useGDC bool // use google default creds
105	var useCEC bool // use compute engine creds
106	if *customCredentialsType != "" {
107		switch *customCredentialsType {
108		case googleDefaultCredsName:
109			useGDC = true
110		case computeEngineCredsName:
111			useCEC = true
112		default:
113			logger.Fatalf("If set, custom_credentials_type can only be set to one of %v or %v",
114				googleDefaultCredsName, computeEngineCredsName)
115		}
116	}
117	if (*useTLS && *useALTS) || (*useTLS && useGDC) || (*useALTS && useGDC) || (*useTLS && useCEC) || (*useALTS && useCEC) {
118		logger.Fatalf("only one of TLS, ALTS, google default creds, or compute engine creds can be used")
119	}
120
121	var credsChosen credsMode
122	switch {
123	case *useTLS:
124		credsChosen = credsTLS
125	case *useALTS:
126		credsChosen = credsALTS
127	case useGDC:
128		credsChosen = credsGoogleDefaultCreds
129	case useCEC:
130		credsChosen = credsComputeEngineCreds
131	}
132
133	resolver.SetDefaultScheme("dns")
134	serverAddr := *serverHost
135	if *serverPort != 0 {
136		serverAddr = net.JoinHostPort(*serverHost, strconv.Itoa(*serverPort))
137	}
138	var opts []grpc.DialOption
139	switch credsChosen {
140	case credsTLS:
141		var roots *x509.CertPool
142		if *testCA {
143			if *caFile == "" {
144				*caFile = testdata.Path("ca.pem")
145			}
146			b, err := ioutil.ReadFile(*caFile)
147			if err != nil {
148				logger.Fatalf("Failed to read root certificate file %q: %v", *caFile, err)
149			}
150			roots = x509.NewCertPool()
151			if !roots.AppendCertsFromPEM(b) {
152				logger.Fatalf("Failed to append certificates: %s", string(b))
153			}
154		}
155		var creds credentials.TransportCredentials
156		if *tlsServerName != "" {
157			creds = credentials.NewClientTLSFromCert(roots, *tlsServerName)
158		} else {
159			creds = credentials.NewTLS(&tls.Config{RootCAs: roots})
160		}
161		opts = append(opts, grpc.WithTransportCredentials(creds))
162	case credsALTS:
163		altsOpts := alts.DefaultClientOptions()
164		if *altsHSAddr != "" {
165			altsOpts.HandshakerServiceAddress = *altsHSAddr
166		}
167		altsTC := alts.NewClientCreds(altsOpts)
168		opts = append(opts, grpc.WithTransportCredentials(altsTC))
169	case credsGoogleDefaultCreds:
170		opts = append(opts, grpc.WithCredentialsBundle(google.NewDefaultCredentials()))
171	case credsComputeEngineCreds:
172		opts = append(opts, grpc.WithCredentialsBundle(google.NewComputeEngineCredentials()))
173	case credsNone:
174		opts = append(opts, grpc.WithInsecure())
175	default:
176		logger.Fatal("Invalid creds")
177	}
178	if credsChosen == credsTLS {
179		if *testCase == "compute_engine_creds" {
180			opts = append(opts, grpc.WithPerRPCCredentials(oauth.NewComputeEngine()))
181		} else if *testCase == "service_account_creds" {
182			jwtCreds, err := oauth.NewServiceAccountFromFile(*serviceAccountKeyFile, *oauthScope)
183			if err != nil {
184				logger.Fatalf("Failed to create JWT credentials: %v", err)
185			}
186			opts = append(opts, grpc.WithPerRPCCredentials(jwtCreds))
187		} else if *testCase == "jwt_token_creds" {
188			jwtCreds, err := oauth.NewJWTAccessFromFile(*serviceAccountKeyFile)
189			if err != nil {
190				logger.Fatalf("Failed to create JWT credentials: %v", err)
191			}
192			opts = append(opts, grpc.WithPerRPCCredentials(jwtCreds))
193		} else if *testCase == "oauth2_auth_token" {
194			opts = append(opts, grpc.WithPerRPCCredentials(oauth.NewOauthAccess(interop.GetToken(*serviceAccountKeyFile, *oauthScope))))
195		}
196	}
197	if len(*serviceConfigJSON) > 0 {
198		opts = append(opts, grpc.WithDisableServiceConfig(), grpc.WithDefaultServiceConfig(*serviceConfigJSON))
199	}
200	opts = append(opts, grpc.WithBlock())
201	conn, err := grpc.Dial(serverAddr, opts...)
202	if err != nil {
203		logger.Fatalf("Fail to dial: %v", err)
204	}
205	defer conn.Close()
206	tc := testgrpc.NewTestServiceClient(conn)
207	switch *testCase {
208	case "empty_unary":
209		interop.DoEmptyUnaryCall(tc)
210		logger.Infoln("EmptyUnaryCall done")
211	case "large_unary":
212		interop.DoLargeUnaryCall(tc)
213		logger.Infoln("LargeUnaryCall done")
214	case "client_streaming":
215		interop.DoClientStreaming(tc)
216		logger.Infoln("ClientStreaming done")
217	case "server_streaming":
218		interop.DoServerStreaming(tc)
219		logger.Infoln("ServerStreaming done")
220	case "ping_pong":
221		interop.DoPingPong(tc)
222		logger.Infoln("Pingpong done")
223	case "empty_stream":
224		interop.DoEmptyStream(tc)
225		logger.Infoln("Emptystream done")
226	case "timeout_on_sleeping_server":
227		interop.DoTimeoutOnSleepingServer(tc)
228		logger.Infoln("TimeoutOnSleepingServer done")
229	case "compute_engine_creds":
230		if credsChosen != credsTLS {
231			logger.Fatalf("TLS credentials need to be set for compute_engine_creds test case.")
232		}
233		interop.DoComputeEngineCreds(tc, *defaultServiceAccount, *oauthScope)
234		logger.Infoln("ComputeEngineCreds done")
235	case "service_account_creds":
236		if credsChosen != credsTLS {
237			logger.Fatalf("TLS credentials need to be set for service_account_creds test case.")
238		}
239		interop.DoServiceAccountCreds(tc, *serviceAccountKeyFile, *oauthScope)
240		logger.Infoln("ServiceAccountCreds done")
241	case "jwt_token_creds":
242		if credsChosen != credsTLS {
243			logger.Fatalf("TLS credentials need to be set for jwt_token_creds test case.")
244		}
245		interop.DoJWTTokenCreds(tc, *serviceAccountKeyFile)
246		logger.Infoln("JWTtokenCreds done")
247	case "per_rpc_creds":
248		if credsChosen != credsTLS {
249			logger.Fatalf("TLS credentials need to be set for per_rpc_creds test case.")
250		}
251		interop.DoPerRPCCreds(tc, *serviceAccountKeyFile, *oauthScope)
252		logger.Infoln("PerRPCCreds done")
253	case "oauth2_auth_token":
254		if credsChosen != credsTLS {
255			logger.Fatalf("TLS credentials need to be set for oauth2_auth_token test case.")
256		}
257		interop.DoOauth2TokenCreds(tc, *serviceAccountKeyFile, *oauthScope)
258		logger.Infoln("Oauth2TokenCreds done")
259	case "google_default_credentials":
260		if credsChosen != credsGoogleDefaultCreds {
261			logger.Fatalf("GoogleDefaultCredentials need to be set for google_default_credentials test case.")
262		}
263		interop.DoGoogleDefaultCredentials(tc, *defaultServiceAccount)
264		logger.Infoln("GoogleDefaultCredentials done")
265	case "compute_engine_channel_credentials":
266		if credsChosen != credsComputeEngineCreds {
267			logger.Fatalf("ComputeEngineCreds need to be set for compute_engine_channel_credentials test case.")
268		}
269		interop.DoComputeEngineChannelCredentials(tc, *defaultServiceAccount)
270		logger.Infoln("ComputeEngineChannelCredentials done")
271	case "cancel_after_begin":
272		interop.DoCancelAfterBegin(tc)
273		logger.Infoln("CancelAfterBegin done")
274	case "cancel_after_first_response":
275		interop.DoCancelAfterFirstResponse(tc)
276		logger.Infoln("CancelAfterFirstResponse done")
277	case "status_code_and_message":
278		interop.DoStatusCodeAndMessage(tc)
279		logger.Infoln("StatusCodeAndMessage done")
280	case "special_status_message":
281		interop.DoSpecialStatusMessage(tc)
282		logger.Infoln("SpecialStatusMessage done")
283	case "custom_metadata":
284		interop.DoCustomMetadata(tc)
285		logger.Infoln("CustomMetadata done")
286	case "unimplemented_method":
287		interop.DoUnimplementedMethod(conn)
288		logger.Infoln("UnimplementedMethod done")
289	case "unimplemented_service":
290		interop.DoUnimplementedService(testgrpc.NewUnimplementedServiceClient(conn))
291		logger.Infoln("UnimplementedService done")
292	case "pick_first_unary":
293		interop.DoPickFirstUnary(tc)
294		logger.Infoln("PickFirstUnary done")
295	default:
296		logger.Fatal("Unsupported test case: ", *testCase)
297	}
298}
299