client_linux.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. *
  3. * Copyright 2019 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 grpclb_fallback is an interop test client for grpclb fallback.
  19. package main
  20. import (
  21. "context"
  22. "flag"
  23. "log"
  24. "net"
  25. "os"
  26. "os/exec"
  27. "syscall"
  28. "time"
  29. "golang.org/x/sys/unix"
  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/xds/googledirectpath"
  36. testgrpc "google.golang.org/grpc/interop/grpc_testing"
  37. testpb "google.golang.org/grpc/interop/grpc_testing"
  38. )
  39. var (
  40. customCredentialsType = flag.String("custom_credentials_type", "", "Client creds to use")
  41. serverURI = flag.String("server_uri", "dns:///staging-grpc-directpath-fallback-test.googleapis.com:443", "The server host name")
  42. induceFallbackCmd = flag.String("induce_fallback_cmd", "", "Command to induce fallback e.g. by making certain addresses unroutable")
  43. fallbackDeadlineSeconds = flag.Int("fallback_deadline_seconds", 1, "How long to wait for fallback to happen after induce_fallback_cmd")
  44. testCase = flag.String("test_case", "",
  45. `Configure different test cases. Valid options are:
  46. fallback_before_startup : LB/backend connections fail before RPC's have been made;
  47. fallback_after_startup : LB/backend connections fail after RPC's have been made;`)
  48. infoLog = log.New(os.Stderr, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
  49. errorLog = log.New(os.Stderr, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)
  50. )
  51. func doRPCAndGetPath(client testgrpc.TestServiceClient, timeout time.Duration) testpb.GrpclbRouteType {
  52. infoLog.Printf("doRPCAndGetPath timeout:%v\n", timeout)
  53. ctx, cancel := context.WithTimeout(context.Background(), timeout)
  54. defer cancel()
  55. req := &testpb.SimpleRequest{
  56. FillGrpclbRouteType: true,
  57. }
  58. reply, err := client.UnaryCall(ctx, req)
  59. if err != nil {
  60. infoLog.Printf("doRPCAndGetPath error:%v\n", err)
  61. return testpb.GrpclbRouteType_GRPCLB_ROUTE_TYPE_UNKNOWN
  62. }
  63. g := reply.GetGrpclbRouteType()
  64. infoLog.Printf("doRPCAndGetPath got grpclb route type: %v\n", g)
  65. if g != testpb.GrpclbRouteType_GRPCLB_ROUTE_TYPE_FALLBACK && g != testpb.GrpclbRouteType_GRPCLB_ROUTE_TYPE_BACKEND {
  66. errorLog.Fatalf("Expected grpclb route type to be either backend or fallback; got: %d", g)
  67. }
  68. return g
  69. }
  70. func dialTCPUserTimeout(ctx context.Context, addr string) (net.Conn, error) {
  71. control := func(network, address string, c syscall.RawConn) error {
  72. var syscallErr error
  73. controlErr := c.Control(func(fd uintptr) {
  74. syscallErr = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT, 20000)
  75. })
  76. if syscallErr != nil {
  77. errorLog.Fatalf("syscall error setting sockopt TCP_USER_TIMEOUT: %v", syscallErr)
  78. }
  79. if controlErr != nil {
  80. errorLog.Fatalf("control error setting sockopt TCP_USER_TIMEOUT: %v", syscallErr)
  81. }
  82. return nil
  83. }
  84. d := &net.Dialer{
  85. Control: control,
  86. }
  87. return d.DialContext(ctx, "tcp", addr)
  88. }
  89. func createTestConn() *grpc.ClientConn {
  90. opts := []grpc.DialOption{
  91. grpc.WithContextDialer(dialTCPUserTimeout),
  92. }
  93. switch *customCredentialsType {
  94. case "tls":
  95. creds := credentials.NewClientTLSFromCert(nil, "")
  96. opts = append(opts, grpc.WithTransportCredentials(creds))
  97. case "alts":
  98. creds := alts.NewClientCreds(alts.DefaultClientOptions())
  99. opts = append(opts, grpc.WithTransportCredentials(creds))
  100. case "google_default_credentials":
  101. opts = append(opts, grpc.WithCredentialsBundle(google.NewDefaultCredentials()))
  102. case "compute_engine_channel_creds":
  103. opts = append(opts, grpc.WithCredentialsBundle(google.NewComputeEngineCredentials()))
  104. default:
  105. errorLog.Fatalf("Invalid --custom_credentials_type:%v", *customCredentialsType)
  106. }
  107. conn, err := grpc.Dial(*serverURI, opts...)
  108. if err != nil {
  109. errorLog.Fatalf("Fail to dial: %v", err)
  110. }
  111. return conn
  112. }
  113. func runCmd(command string) {
  114. infoLog.Printf("Running cmd:|%v|\n", command)
  115. if err := exec.Command("bash", "-c", command).Run(); err != nil {
  116. errorLog.Fatalf("error running cmd:|%v| : %v", command, err)
  117. }
  118. }
  119. func waitForFallbackAndDoRPCs(client testgrpc.TestServiceClient, fallbackDeadline time.Time) {
  120. fallbackRetryCount := 0
  121. fellBack := false
  122. for time.Now().Before(fallbackDeadline) {
  123. g := doRPCAndGetPath(client, 20*time.Second)
  124. if g == testpb.GrpclbRouteType_GRPCLB_ROUTE_TYPE_FALLBACK {
  125. infoLog.Println("Made one successul RPC to a fallback. Now expect the same for the rest.")
  126. fellBack = true
  127. break
  128. } else if g == testpb.GrpclbRouteType_GRPCLB_ROUTE_TYPE_BACKEND {
  129. errorLog.Fatalf("Got RPC type backend. This suggests an error in test implementation")
  130. } else {
  131. infoLog.Println("Retryable RPC failure on iteration:", fallbackRetryCount)
  132. }
  133. fallbackRetryCount++
  134. }
  135. if !fellBack {
  136. infoLog.Fatalf("Didn't fall back before deadline: %v\n", fallbackDeadline)
  137. }
  138. for i := 0; i < 30; i++ {
  139. if g := doRPCAndGetPath(client, 20*time.Second); g != testpb.GrpclbRouteType_GRPCLB_ROUTE_TYPE_FALLBACK {
  140. errorLog.Fatalf("Expected RPC to take grpclb route type FALLBACK. Got: %v", g)
  141. }
  142. time.Sleep(time.Second)
  143. }
  144. }
  145. func doFallbackBeforeStartup() {
  146. runCmd(*induceFallbackCmd)
  147. fallbackDeadline := time.Now().Add(time.Duration(*fallbackDeadlineSeconds) * time.Second)
  148. conn := createTestConn()
  149. defer conn.Close()
  150. client := testgrpc.NewTestServiceClient(conn)
  151. waitForFallbackAndDoRPCs(client, fallbackDeadline)
  152. }
  153. func doFallbackAfterStartup() {
  154. conn := createTestConn()
  155. defer conn.Close()
  156. client := testgrpc.NewTestServiceClient(conn)
  157. if g := doRPCAndGetPath(client, 20*time.Second); g != testpb.GrpclbRouteType_GRPCLB_ROUTE_TYPE_BACKEND {
  158. errorLog.Fatalf("Expected RPC to take grpclb route type BACKEND. Got: %v", g)
  159. }
  160. runCmd(*induceFallbackCmd)
  161. fallbackDeadline := time.Now().Add(time.Duration(*fallbackDeadlineSeconds) * time.Second)
  162. waitForFallbackAndDoRPCs(client, fallbackDeadline)
  163. }
  164. func main() {
  165. flag.Parse()
  166. if len(*induceFallbackCmd) == 0 {
  167. errorLog.Fatalf("--induce_fallback_cmd unset")
  168. }
  169. switch *testCase {
  170. case "fallback_before_startup":
  171. doFallbackBeforeStartup()
  172. log.Printf("FallbackBeforeStartup done!\n")
  173. case "fallback_after_startup":
  174. doFallbackAfterStartup()
  175. log.Printf("FallbackAfterStartup done!\n")
  176. default:
  177. errorLog.Fatalf("Unsupported test case: %v", *testCase)
  178. }
  179. }