client.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  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. // Binary client is an interop client.
  19. //
  20. // See interop test case descriptions [here].
  21. //
  22. // [here]: https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md
  23. package main
  24. import (
  25. "context"
  26. "crypto/tls"
  27. "crypto/x509"
  28. "flag"
  29. "net"
  30. "os"
  31. "strconv"
  32. "strings"
  33. "time"
  34. "golang.org/x/oauth2"
  35. "google.golang.org/grpc"
  36. "google.golang.org/grpc/credentials"
  37. "google.golang.org/grpc/credentials/alts"
  38. "google.golang.org/grpc/credentials/google"
  39. "google.golang.org/grpc/credentials/insecure"
  40. "google.golang.org/grpc/credentials/oauth"
  41. "google.golang.org/grpc/grpclog"
  42. "google.golang.org/grpc/interop"
  43. "google.golang.org/grpc/metadata"
  44. "google.golang.org/grpc/resolver"
  45. "google.golang.org/grpc/testdata"
  46. _ "google.golang.org/grpc/balancer/grpclb" // Register the grpclb load balancing policy.
  47. _ "google.golang.org/grpc/balancer/rls" // Register the RLS load balancing policy.
  48. _ "google.golang.org/grpc/xds/googledirectpath" // Register xDS resolver required for c2p directpath.
  49. testgrpc "google.golang.org/grpc/interop/grpc_testing"
  50. )
  51. const (
  52. googleDefaultCredsName = "google_default_credentials"
  53. computeEngineCredsName = "compute_engine_channel_creds"
  54. )
  55. var (
  56. caFile = flag.String("ca_file", "", "The file containning the CA root cert file")
  57. useTLS = flag.Bool("use_tls", false, "Connection uses TLS if true")
  58. useALTS = flag.Bool("use_alts", false, "Connection uses ALTS if true (this option can only be used on GCP)")
  59. customCredentialsType = flag.String("custom_credentials_type", "", "Custom creds to use, excluding TLS or ALTS")
  60. altsHSAddr = flag.String("alts_handshaker_service_address", "", "ALTS handshaker gRPC service address")
  61. testCA = flag.Bool("use_test_ca", false, "Whether to replace platform root CAs with test CA as the CA root")
  62. serviceAccountKeyFile = flag.String("service_account_key_file", "", "Path to service account json key file")
  63. oauthScope = flag.String("oauth_scope", "", "The scope for OAuth2 tokens")
  64. defaultServiceAccount = flag.String("default_service_account", "", "Email of GCE default service account")
  65. serverHost = flag.String("server_host", "localhost", "The server host name")
  66. serverPort = flag.Int("server_port", 10000, "The server port number")
  67. serviceConfigJSON = flag.String("service_config_json", "", "Disables service config lookups and sets the provided string as the default service config.")
  68. soakIterations = flag.Int("soak_iterations", 10, "The number of iterations to use for the two soak tests: rpc_soak and channel_soak")
  69. soakMaxFailures = flag.Int("soak_max_failures", 0, "The number of iterations in soak tests that are allowed to fail (either due to non-OK status code or exceeding the per-iteration max acceptable latency).")
  70. soakPerIterationMaxAcceptableLatencyMs = flag.Int("soak_per_iteration_max_acceptable_latency_ms", 1000, "The number of milliseconds a single iteration in the two soak tests (rpc_soak and channel_soak) should take.")
  71. soakOverallTimeoutSeconds = flag.Int("soak_overall_timeout_seconds", 10, "The overall number of seconds after which a soak test should stop and fail, if the desired number of iterations have not yet completed.")
  72. soakMinTimeMsBetweenRPCs = flag.Int("soak_min_time_ms_between_rpcs", 0, "The minimum time in milliseconds between consecutive RPCs in a soak test (rpc_soak or channel_soak), useful for limiting QPS")
  73. 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.")
  74. additionalMetadata = flag.String("additional_metadata", "", "Additional metadata to send in each request, as a semicolon-separated list of key:value pairs.")
  75. testCase = flag.String("test_case", "large_unary",
  76. `Configure different test cases. Valid options are:
  77. empty_unary : empty (zero bytes) request and response;
  78. large_unary : single request and (large) response;
  79. client_streaming : request streaming with single response;
  80. server_streaming : single request with response streaming;
  81. ping_pong : full-duplex streaming;
  82. empty_stream : full-duplex streaming with zero message;
  83. timeout_on_sleeping_server: fullduplex streaming on a sleeping server;
  84. compute_engine_creds: large_unary with compute engine auth;
  85. service_account_creds: large_unary with service account auth;
  86. jwt_token_creds: large_unary with jwt token auth;
  87. per_rpc_creds: large_unary with per rpc token;
  88. oauth2_auth_token: large_unary with oauth2 token auth;
  89. google_default_credentials: large_unary with google default credentials
  90. compute_engine_channel_credentials: large_unary with compute engine creds
  91. cancel_after_begin: cancellation after metadata has been sent but before payloads are sent;
  92. cancel_after_first_response: cancellation after receiving 1st message from the server;
  93. status_code_and_message: status code propagated back to client;
  94. special_status_message: Unicode and whitespace is correctly processed in status message;
  95. custom_metadata: server will echo custom metadata;
  96. unimplemented_method: client attempts to call unimplemented method;
  97. unimplemented_service: client attempts to call unimplemented service;
  98. pick_first_unary: all requests are sent to one server despite multiple servers are resolved;
  99. orca_per_rpc: the client verifies ORCA per-RPC metrics are provided;
  100. orca_oob: the client verifies ORCA out-of-band metrics are provided.`)
  101. logger = grpclog.Component("interop")
  102. )
  103. type credsMode uint8
  104. const (
  105. credsNone credsMode = iota
  106. credsTLS
  107. credsALTS
  108. credsGoogleDefaultCreds
  109. credsComputeEngineCreds
  110. )
  111. // Parses the --additional_metadata flag and returns metadata to send on each RPC,
  112. // formatted as per https://pkg.go.dev/google.golang.org/grpc/metadata#Pairs.
  113. // Allow any character but semicolons in values. If the flag is empty, return a nil map.
  114. func parseAdditionalMetadataFlag() []string {
  115. if len(*additionalMetadata) == 0 {
  116. return nil
  117. }
  118. r := *additionalMetadata
  119. addMd := make([]string, 0)
  120. for len(r) > 0 {
  121. i := strings.Index(r, ":")
  122. if i < 0 {
  123. logger.Fatalf("Error parsing --additional_metadata flag: missing colon separator")
  124. }
  125. addMd = append(addMd, r[:i]) // append key
  126. r = r[i+1:]
  127. i = strings.Index(r, ";")
  128. // append value
  129. if i < 0 {
  130. addMd = append(addMd, r)
  131. break
  132. }
  133. addMd = append(addMd, r[:i])
  134. r = r[i+1:]
  135. }
  136. return addMd
  137. }
  138. func main() {
  139. flag.Parse()
  140. logger.Infof("Client running with test case %q", *testCase)
  141. var useGDC bool // use google default creds
  142. var useCEC bool // use compute engine creds
  143. if *customCredentialsType != "" {
  144. switch *customCredentialsType {
  145. case googleDefaultCredsName:
  146. useGDC = true
  147. case computeEngineCredsName:
  148. useCEC = true
  149. default:
  150. logger.Fatalf("If set, custom_credentials_type can only be set to one of %v or %v",
  151. googleDefaultCredsName, computeEngineCredsName)
  152. }
  153. }
  154. if (*useTLS && *useALTS) || (*useTLS && useGDC) || (*useALTS && useGDC) || (*useTLS && useCEC) || (*useALTS && useCEC) {
  155. logger.Fatalf("only one of TLS, ALTS, google default creds, or compute engine creds can be used")
  156. }
  157. var credsChosen credsMode
  158. switch {
  159. case *useTLS:
  160. credsChosen = credsTLS
  161. case *useALTS:
  162. credsChosen = credsALTS
  163. case useGDC:
  164. credsChosen = credsGoogleDefaultCreds
  165. case useCEC:
  166. credsChosen = credsComputeEngineCreds
  167. }
  168. resolver.SetDefaultScheme("dns")
  169. serverAddr := *serverHost
  170. if *serverPort != 0 {
  171. serverAddr = net.JoinHostPort(*serverHost, strconv.Itoa(*serverPort))
  172. }
  173. var opts []grpc.DialOption
  174. switch credsChosen {
  175. case credsTLS:
  176. var roots *x509.CertPool
  177. if *testCA {
  178. if *caFile == "" {
  179. *caFile = testdata.Path("ca.pem")
  180. }
  181. b, err := os.ReadFile(*caFile)
  182. if err != nil {
  183. logger.Fatalf("Failed to read root certificate file %q: %v", *caFile, err)
  184. }
  185. roots = x509.NewCertPool()
  186. if !roots.AppendCertsFromPEM(b) {
  187. logger.Fatalf("Failed to append certificates: %s", string(b))
  188. }
  189. }
  190. var creds credentials.TransportCredentials
  191. if *tlsServerName != "" {
  192. creds = credentials.NewClientTLSFromCert(roots, *tlsServerName)
  193. } else {
  194. creds = credentials.NewTLS(&tls.Config{RootCAs: roots})
  195. }
  196. opts = append(opts, grpc.WithTransportCredentials(creds))
  197. case credsALTS:
  198. altsOpts := alts.DefaultClientOptions()
  199. if *altsHSAddr != "" {
  200. altsOpts.HandshakerServiceAddress = *altsHSAddr
  201. }
  202. altsTC := alts.NewClientCreds(altsOpts)
  203. opts = append(opts, grpc.WithTransportCredentials(altsTC))
  204. case credsGoogleDefaultCreds:
  205. opts = append(opts, grpc.WithCredentialsBundle(google.NewDefaultCredentials()))
  206. case credsComputeEngineCreds:
  207. opts = append(opts, grpc.WithCredentialsBundle(google.NewComputeEngineCredentials()))
  208. case credsNone:
  209. opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
  210. default:
  211. logger.Fatal("Invalid creds")
  212. }
  213. if credsChosen == credsTLS {
  214. if *testCase == "compute_engine_creds" {
  215. opts = append(opts, grpc.WithPerRPCCredentials(oauth.NewComputeEngine()))
  216. } else if *testCase == "service_account_creds" {
  217. jwtCreds, err := oauth.NewServiceAccountFromFile(*serviceAccountKeyFile, *oauthScope)
  218. if err != nil {
  219. logger.Fatalf("Failed to create JWT credentials: %v", err)
  220. }
  221. opts = append(opts, grpc.WithPerRPCCredentials(jwtCreds))
  222. } else if *testCase == "jwt_token_creds" {
  223. jwtCreds, err := oauth.NewJWTAccessFromFile(*serviceAccountKeyFile)
  224. if err != nil {
  225. logger.Fatalf("Failed to create JWT credentials: %v", err)
  226. }
  227. opts = append(opts, grpc.WithPerRPCCredentials(jwtCreds))
  228. } else if *testCase == "oauth2_auth_token" {
  229. opts = append(opts, grpc.WithPerRPCCredentials(oauth.TokenSource{TokenSource: oauth2.StaticTokenSource(interop.GetToken(*serviceAccountKeyFile, *oauthScope))}))
  230. }
  231. }
  232. if len(*serviceConfigJSON) > 0 {
  233. opts = append(opts, grpc.WithDisableServiceConfig(), grpc.WithDefaultServiceConfig(*serviceConfigJSON))
  234. }
  235. if addMd := parseAdditionalMetadataFlag(); addMd != nil {
  236. unaryAddMd := func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
  237. ctx = metadata.AppendToOutgoingContext(ctx, addMd...)
  238. return invoker(ctx, method, req, reply, cc, opts...)
  239. }
  240. streamingAddMd := func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
  241. ctx = metadata.AppendToOutgoingContext(ctx, addMd...)
  242. return streamer(ctx, desc, cc, method, opts...)
  243. }
  244. opts = append(opts, grpc.WithUnaryInterceptor(unaryAddMd), grpc.WithStreamInterceptor(streamingAddMd))
  245. }
  246. conn, err := grpc.Dial(serverAddr, opts...)
  247. if err != nil {
  248. logger.Fatalf("Fail to dial: %v", err)
  249. }
  250. defer conn.Close()
  251. tc := testgrpc.NewTestServiceClient(conn)
  252. switch *testCase {
  253. case "empty_unary":
  254. interop.DoEmptyUnaryCall(tc)
  255. logger.Infoln("EmptyUnaryCall done")
  256. case "large_unary":
  257. interop.DoLargeUnaryCall(tc)
  258. logger.Infoln("LargeUnaryCall done")
  259. case "client_streaming":
  260. interop.DoClientStreaming(tc)
  261. logger.Infoln("ClientStreaming done")
  262. case "server_streaming":
  263. interop.DoServerStreaming(tc)
  264. logger.Infoln("ServerStreaming done")
  265. case "ping_pong":
  266. interop.DoPingPong(tc)
  267. logger.Infoln("Pingpong done")
  268. case "empty_stream":
  269. interop.DoEmptyStream(tc)
  270. logger.Infoln("Emptystream done")
  271. case "timeout_on_sleeping_server":
  272. interop.DoTimeoutOnSleepingServer(tc)
  273. logger.Infoln("TimeoutOnSleepingServer done")
  274. case "compute_engine_creds":
  275. if credsChosen != credsTLS {
  276. logger.Fatalf("TLS credentials need to be set for compute_engine_creds test case.")
  277. }
  278. interop.DoComputeEngineCreds(tc, *defaultServiceAccount, *oauthScope)
  279. logger.Infoln("ComputeEngineCreds done")
  280. case "service_account_creds":
  281. if credsChosen != credsTLS {
  282. logger.Fatalf("TLS credentials need to be set for service_account_creds test case.")
  283. }
  284. interop.DoServiceAccountCreds(tc, *serviceAccountKeyFile, *oauthScope)
  285. logger.Infoln("ServiceAccountCreds done")
  286. case "jwt_token_creds":
  287. if credsChosen != credsTLS {
  288. logger.Fatalf("TLS credentials need to be set for jwt_token_creds test case.")
  289. }
  290. interop.DoJWTTokenCreds(tc, *serviceAccountKeyFile)
  291. logger.Infoln("JWTtokenCreds done")
  292. case "per_rpc_creds":
  293. if credsChosen != credsTLS {
  294. logger.Fatalf("TLS credentials need to be set for per_rpc_creds test case.")
  295. }
  296. interop.DoPerRPCCreds(tc, *serviceAccountKeyFile, *oauthScope)
  297. logger.Infoln("PerRPCCreds done")
  298. case "oauth2_auth_token":
  299. if credsChosen != credsTLS {
  300. logger.Fatalf("TLS credentials need to be set for oauth2_auth_token test case.")
  301. }
  302. interop.DoOauth2TokenCreds(tc, *serviceAccountKeyFile, *oauthScope)
  303. logger.Infoln("Oauth2TokenCreds done")
  304. case "google_default_credentials":
  305. if credsChosen != credsGoogleDefaultCreds {
  306. logger.Fatalf("GoogleDefaultCredentials need to be set for google_default_credentials test case.")
  307. }
  308. interop.DoGoogleDefaultCredentials(tc, *defaultServiceAccount)
  309. logger.Infoln("GoogleDefaultCredentials done")
  310. case "compute_engine_channel_credentials":
  311. if credsChosen != credsComputeEngineCreds {
  312. logger.Fatalf("ComputeEngineCreds need to be set for compute_engine_channel_credentials test case.")
  313. }
  314. interop.DoComputeEngineChannelCredentials(tc, *defaultServiceAccount)
  315. logger.Infoln("ComputeEngineChannelCredentials done")
  316. case "cancel_after_begin":
  317. interop.DoCancelAfterBegin(tc)
  318. logger.Infoln("CancelAfterBegin done")
  319. case "cancel_after_first_response":
  320. interop.DoCancelAfterFirstResponse(tc)
  321. logger.Infoln("CancelAfterFirstResponse done")
  322. case "status_code_and_message":
  323. interop.DoStatusCodeAndMessage(tc)
  324. logger.Infoln("StatusCodeAndMessage done")
  325. case "special_status_message":
  326. interop.DoSpecialStatusMessage(tc)
  327. logger.Infoln("SpecialStatusMessage done")
  328. case "custom_metadata":
  329. interop.DoCustomMetadata(tc)
  330. logger.Infoln("CustomMetadata done")
  331. case "unimplemented_method":
  332. interop.DoUnimplementedMethod(conn)
  333. logger.Infoln("UnimplementedMethod done")
  334. case "unimplemented_service":
  335. interop.DoUnimplementedService(testgrpc.NewUnimplementedServiceClient(conn))
  336. logger.Infoln("UnimplementedService done")
  337. case "pick_first_unary":
  338. interop.DoPickFirstUnary(tc)
  339. logger.Infoln("PickFirstUnary done")
  340. case "rpc_soak":
  341. interop.DoSoakTest(tc, serverAddr, opts, false /* resetChannel */, *soakIterations, *soakMaxFailures, time.Duration(*soakPerIterationMaxAcceptableLatencyMs)*time.Millisecond, time.Duration(*soakMinTimeMsBetweenRPCs)*time.Millisecond, time.Now().Add(time.Duration(*soakOverallTimeoutSeconds)*time.Second))
  342. logger.Infoln("RpcSoak done")
  343. case "channel_soak":
  344. interop.DoSoakTest(tc, serverAddr, opts, true /* resetChannel */, *soakIterations, *soakMaxFailures, time.Duration(*soakPerIterationMaxAcceptableLatencyMs)*time.Millisecond, time.Duration(*soakMinTimeMsBetweenRPCs)*time.Millisecond, time.Now().Add(time.Duration(*soakOverallTimeoutSeconds)*time.Second))
  345. logger.Infoln("ChannelSoak done")
  346. case "orca_per_rpc":
  347. interop.DoORCAPerRPCTest(tc)
  348. logger.Infoln("ORCAPerRPC done")
  349. case "orca_oob":
  350. interop.DoORCAOOBTest(tc)
  351. logger.Infoln("ORCAOOB done")
  352. default:
  353. logger.Fatal("Unsupported test case: ", *testCase)
  354. }
  355. }