github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/go-control-plane/pkg/test/server.go (about)

     1  // Package test contains test utilities
     2  package test
     3  
     4  import (
     5  	"context"
     6  	"fmt"
     7  	"log"
     8  	"net"
     9  	"net/http"
    10  	"time"
    11  
    12  	"github.com/hxx258456/ccgo/grpc"
    13  	"github.com/hxx258456/ccgo/grpc/keepalive"
    14  
    15  	server "github.com/hxx258456/ccgo/go-control-plane/pkg/server/v3"
    16  	"github.com/hxx258456/ccgo/go-control-plane/pkg/test/v3"
    17  
    18  	gcplogger "github.com/hxx258456/ccgo/go-control-plane/pkg/log"
    19  )
    20  
    21  const (
    22  	grpcKeepaliveTime        = 30 * time.Second
    23  	grpcKeepaliveTimeout     = 5 * time.Second
    24  	grpcKeepaliveMinTime     = 30 * time.Second
    25  	grpcMaxConcurrentStreams = 1000000
    26  )
    27  
    28  // HTTPGateway is a custom implementation of [gRPC gateway](https://github.com/grpc-ecosystem/grpc-gateway)
    29  // specialized to Envoy xDS API.
    30  type HTTPGateway struct {
    31  	// Log is an optional log for errors in response write
    32  	Log gcplogger.Logger
    33  
    34  	Gateway server.HTTPGateway
    35  }
    36  
    37  // RunAccessLogServer starts an accesslog server.
    38  func RunAccessLogServer(ctx context.Context, als *test.AccessLogService, alsPort uint) {
    39  	grpcServer := grpc.NewServer()
    40  	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", alsPort))
    41  	if err != nil {
    42  		log.Fatal(err)
    43  	}
    44  
    45  	test.RegisterAccessLogServer(grpcServer, als)
    46  	log.Printf("access log server listening on %d\n", alsPort)
    47  
    48  	go func() {
    49  		if err = grpcServer.Serve(lis); err != nil {
    50  			log.Println(err)
    51  		}
    52  	}()
    53  	<-ctx.Done()
    54  
    55  	grpcServer.GracefulStop()
    56  }
    57  
    58  // RunManagementServer starts an xDS server at the given port.
    59  func RunManagementServer(ctx context.Context, srv server.Server, port uint) {
    60  	// gRPC golang library sets a very small upper bound for the number gRPC/h2
    61  	// streams over a single TCP connection. If a proxy multiplexes requests over
    62  	// a single connection to the management server, then it might lead to
    63  	// availability problems. Keepalive timeouts based on connection_keepalive parameter https://www.envoyproxy.io/docs/envoy/latest/configuration/overview/examples#dynamic
    64  	var grpcOptions []grpc.ServerOption
    65  	grpcOptions = append(grpcOptions,
    66  		grpc.MaxConcurrentStreams(grpcMaxConcurrentStreams),
    67  		grpc.KeepaliveParams(keepalive.ServerParameters{
    68  			Time:    grpcKeepaliveTime,
    69  			Timeout: grpcKeepaliveTimeout,
    70  		}),
    71  		grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
    72  			MinTime:             grpcKeepaliveMinTime,
    73  			PermitWithoutStream: true,
    74  		}),
    75  	)
    76  	grpcServer := grpc.NewServer(grpcOptions...)
    77  
    78  	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
    79  	if err != nil {
    80  		log.Fatal(err)
    81  	}
    82  
    83  	test.RegisterServer(grpcServer, srv)
    84  
    85  	log.Printf("management server listening on %d\n", port)
    86  	go func() {
    87  		if err = grpcServer.Serve(lis); err != nil {
    88  			log.Println(err)
    89  		}
    90  	}()
    91  	<-ctx.Done()
    92  
    93  	grpcServer.GracefulStop()
    94  }
    95  
    96  // RunManagementGateway starts an HTTP gateway to an xDS server.
    97  func RunManagementGateway(ctx context.Context, srv server.Server, port uint, lg gcplogger.Logger) {
    98  	log.Printf("gateway listening HTTP/1.1 on %d\n", port)
    99  	server := &http.Server{
   100  		Addr: fmt.Sprintf(":%d", port),
   101  		Handler: &HTTPGateway{
   102  			Gateway: server.HTTPGateway{Log: lg, Server: srv},
   103  			Log:     lg,
   104  		},
   105  	}
   106  	go func() {
   107  		if err := server.ListenAndServe(); err != nil {
   108  			log.Printf("failed to start listening: %s", err)
   109  		}
   110  	}()
   111  	<-ctx.Done()
   112  
   113  	// Cleanup our gateway if we receive a shutdown
   114  	if err := server.Shutdown(ctx); err != nil {
   115  		log.Printf("failed to shut down: %s", err)
   116  	}
   117  }
   118  
   119  func (h *HTTPGateway) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
   120  	bytes, code, err := h.Gateway.ServeHTTP(req)
   121  
   122  	if err != nil {
   123  		http.Error(resp, err.Error(), code)
   124  		return
   125  	}
   126  
   127  	if bytes == nil {
   128  		resp.WriteHeader(http.StatusNotModified)
   129  		return
   130  	}
   131  
   132  	if _, err = resp.Write(bytes); err != nil && h.Log != nil {
   133  		h.Log.Errorf("gateway error: %v", err)
   134  	}
   135  }