...

Source file src/google.golang.org/grpc/interop/grpclb_fallback/client_linux.go

Documentation: google.golang.org/grpc/interop/grpclb_fallback

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

View as plain text