github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/interop/grpclb_fallback/client_linux.go (about)

     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  	grpc "github.com/hxx258456/ccgo/grpc"
    33  	_ "github.com/hxx258456/ccgo/grpc/balancer/grpclb"
    34  	"github.com/hxx258456/ccgo/grpc/credentials"
    35  	"github.com/hxx258456/ccgo/grpc/credentials/alts"
    36  	"github.com/hxx258456/ccgo/grpc/credentials/google"
    37  	_ "github.com/hxx258456/ccgo/grpc/xds/googledirectpath"
    38  	"golang.org/x/sys/unix"
    39  
    40  	testgrpc "github.com/hxx258456/ccgo/grpc/interop/grpc_testing"
    41  	testpb "github.com/hxx258456/ccgo/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  	unrouteLBAndBackendAddrsCmd   = flag.String("unroute_lb_and_backend_addrs_cmd", "", "Command to make LB and backend address unroutable")
    48  	blackholeLBAndBackendAddrsCmd = flag.String("blackhole_lb_and_backend_addrs_cmd", "", "Command to make LB and backend addresses blackholed")
    49  	testCase                      = flag.String("test_case", "",
    50  		`Configure different test cases. Valid options are:
    51          fast_fallback_before_startup : LB/backend connections fail fast before RPC's have been made;
    52          fast_fallback_after_startup : LB/backend connections fail fast after RPC's have been made;
    53          slow_fallback_before_startup : LB/backend connections black hole before RPC's have been made;
    54          slow_fallback_after_startup : LB/backend connections black hole after RPC's have been made;`)
    55  	infoLog  = log.New(os.Stderr, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
    56  	errorLog = log.New(os.Stderr, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)
    57  )
    58  
    59  func doRPCAndGetPath(client testgrpc.TestServiceClient, timeout time.Duration) testpb.GrpclbRouteType {
    60  	infoLog.Printf("doRPCAndGetPath timeout:%v\n", timeout)
    61  	ctx, cancel := context.WithTimeout(context.Background(), timeout)
    62  	defer cancel()
    63  	req := &testpb.SimpleRequest{
    64  		FillGrpclbRouteType: true,
    65  	}
    66  	reply, err := client.UnaryCall(ctx, req)
    67  	if err != nil {
    68  		infoLog.Printf("doRPCAndGetPath error:%v\n", err)
    69  		return testpb.GrpclbRouteType_GRPCLB_ROUTE_TYPE_UNKNOWN
    70  	}
    71  	g := reply.GetGrpclbRouteType()
    72  	infoLog.Printf("doRPCAndGetPath got grpclb route type: %v\n", g)
    73  	if g != testpb.GrpclbRouteType_GRPCLB_ROUTE_TYPE_FALLBACK && g != testpb.GrpclbRouteType_GRPCLB_ROUTE_TYPE_BACKEND {
    74  		errorLog.Fatalf("Expected grpclb route type to be either backend or fallback; got: %d", g)
    75  	}
    76  	return g
    77  }
    78  
    79  func dialTCPUserTimeout(ctx context.Context, addr string) (net.Conn, error) {
    80  	control := func(network, address string, c syscall.RawConn) error {
    81  		var syscallErr error
    82  		controlErr := c.Control(func(fd uintptr) {
    83  			syscallErr = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT, 20000)
    84  		})
    85  		if syscallErr != nil {
    86  			errorLog.Fatalf("syscall error setting sockopt TCP_USER_TIMEOUT: %v", syscallErr)
    87  		}
    88  		if controlErr != nil {
    89  			errorLog.Fatalf("control error setting sockopt TCP_USER_TIMEOUT: %v", syscallErr)
    90  		}
    91  		return nil
    92  	}
    93  	d := &net.Dialer{
    94  		Control: control,
    95  	}
    96  	return d.DialContext(ctx, "tcp", addr)
    97  }
    98  
    99  func createTestConn() *grpc.ClientConn {
   100  	opts := []grpc.DialOption{
   101  		grpc.WithContextDialer(dialTCPUserTimeout),
   102  	}
   103  	switch *customCredentialsType {
   104  	case "tls":
   105  		creds := credentials.NewClientTLSFromCert(nil, "")
   106  		opts = append(opts, grpc.WithTransportCredentials(creds))
   107  	case "alts":
   108  		creds := alts.NewClientCreds(alts.DefaultClientOptions())
   109  		opts = append(opts, grpc.WithTransportCredentials(creds))
   110  	case "google_default_credentials":
   111  		opts = append(opts, grpc.WithCredentialsBundle(google.NewDefaultCredentials()))
   112  	case "compute_engine_channel_creds":
   113  		opts = append(opts, grpc.WithCredentialsBundle(google.NewComputeEngineCredentials()))
   114  	default:
   115  		errorLog.Fatalf("Invalid --custom_credentials_type:%v", *customCredentialsType)
   116  	}
   117  	conn, err := grpc.Dial(*serverURI, opts...)
   118  	if err != nil {
   119  		errorLog.Fatalf("Fail to dial: %v", err)
   120  	}
   121  	return conn
   122  }
   123  
   124  func runCmd(command string) {
   125  	infoLog.Printf("Running cmd:|%v|\n", command)
   126  	if err := exec.Command("bash", "-c", command).Run(); err != nil {
   127  		errorLog.Fatalf("error running cmd:|%v| : %v", command, err)
   128  	}
   129  }
   130  
   131  func waitForFallbackAndDoRPCs(client testgrpc.TestServiceClient, fallbackDeadline time.Time) {
   132  	fallbackRetryCount := 0
   133  	fellBack := false
   134  	for time.Now().Before(fallbackDeadline) {
   135  		g := doRPCAndGetPath(client, 1*time.Second)
   136  		if g == testpb.GrpclbRouteType_GRPCLB_ROUTE_TYPE_FALLBACK {
   137  			infoLog.Println("Made one successul RPC to a fallback. Now expect the same for the rest.")
   138  			fellBack = true
   139  			break
   140  		} else if g == testpb.GrpclbRouteType_GRPCLB_ROUTE_TYPE_BACKEND {
   141  			errorLog.Fatalf("Got RPC type backend. This suggests an error in test implementation")
   142  		} else {
   143  			infoLog.Println("Retryable RPC failure on iteration:", fallbackRetryCount)
   144  		}
   145  		fallbackRetryCount++
   146  	}
   147  	if !fellBack {
   148  		infoLog.Fatalf("Didn't fall back before deadline: %v\n", fallbackDeadline)
   149  	}
   150  	for i := 0; i < 30; i++ {
   151  		if g := doRPCAndGetPath(client, 20*time.Second); g != testpb.GrpclbRouteType_GRPCLB_ROUTE_TYPE_FALLBACK {
   152  			errorLog.Fatalf("Expected RPC to take grpclb route type FALLBACK. Got: %v", g)
   153  		}
   154  		time.Sleep(time.Second)
   155  	}
   156  }
   157  
   158  func doFastFallbackBeforeStartup() {
   159  	runCmd(*unrouteLBAndBackendAddrsCmd)
   160  	fallbackDeadline := time.Now().Add(5 * time.Second)
   161  	conn := createTestConn()
   162  	defer conn.Close()
   163  	client := testgrpc.NewTestServiceClient(conn)
   164  	waitForFallbackAndDoRPCs(client, fallbackDeadline)
   165  }
   166  
   167  func doSlowFallbackBeforeStartup() {
   168  	runCmd(*blackholeLBAndBackendAddrsCmd)
   169  	fallbackDeadline := time.Now().Add(20 * time.Second)
   170  	conn := createTestConn()
   171  	defer conn.Close()
   172  	client := testgrpc.NewTestServiceClient(conn)
   173  	waitForFallbackAndDoRPCs(client, fallbackDeadline)
   174  }
   175  
   176  func doFastFallbackAfterStartup() {
   177  	conn := createTestConn()
   178  	defer conn.Close()
   179  	client := testgrpc.NewTestServiceClient(conn)
   180  	if g := doRPCAndGetPath(client, 20*time.Second); g != testpb.GrpclbRouteType_GRPCLB_ROUTE_TYPE_BACKEND {
   181  		errorLog.Fatalf("Expected RPC to take grpclb route type BACKEND. Got: %v", g)
   182  	}
   183  	runCmd(*unrouteLBAndBackendAddrsCmd)
   184  	fallbackDeadline := time.Now().Add(40 * time.Second)
   185  	waitForFallbackAndDoRPCs(client, fallbackDeadline)
   186  }
   187  
   188  func doSlowFallbackAfterStartup() {
   189  	conn := createTestConn()
   190  	defer conn.Close()
   191  	client := testgrpc.NewTestServiceClient(conn)
   192  	if g := doRPCAndGetPath(client, 20*time.Second); g != testpb.GrpclbRouteType_GRPCLB_ROUTE_TYPE_BACKEND {
   193  		errorLog.Fatalf("Expected RPC to take grpclb route type BACKEND. Got: %v", g)
   194  	}
   195  	runCmd(*blackholeLBAndBackendAddrsCmd)
   196  	fallbackDeadline := time.Now().Add(40 * time.Second)
   197  	waitForFallbackAndDoRPCs(client, fallbackDeadline)
   198  }
   199  
   200  func main() {
   201  	flag.Parse()
   202  	if len(*unrouteLBAndBackendAddrsCmd) == 0 {
   203  		errorLog.Fatalf("--unroute_lb_and_backend_addrs_cmd unset")
   204  	}
   205  	if len(*blackholeLBAndBackendAddrsCmd) == 0 {
   206  		errorLog.Fatalf("--blackhole_lb_and_backend_addrs_cmd unset")
   207  	}
   208  	switch *testCase {
   209  	case "fast_fallback_before_startup":
   210  		doFastFallbackBeforeStartup()
   211  		log.Printf("FastFallbackBeforeStartup done!\n")
   212  	case "fast_fallback_after_startup":
   213  		doFastFallbackAfterStartup()
   214  		log.Printf("FastFallbackAfterStartup done!\n")
   215  	case "slow_fallback_before_startup":
   216  		doSlowFallbackBeforeStartup()
   217  		log.Printf("SlowFallbackBeforeStartup done!\n")
   218  	case "slow_fallback_after_startup":
   219  		doSlowFallbackAfterStartup()
   220  		log.Printf("SlowFallbackAfterStartup done!\n")
   221  	default:
   222  		errorLog.Fatalf("Unsupported test case: %v", *testCase)
   223  	}
   224  }