github.com/outbrain/consul@v1.4.5/agent/checks/grpc.go (about) 1 package checks 2 3 import ( 4 "context" 5 "crypto/tls" 6 "fmt" 7 "strings" 8 "time" 9 10 "google.golang.org/grpc" 11 "google.golang.org/grpc/credentials" 12 hv1 "google.golang.org/grpc/health/grpc_health_v1" 13 ) 14 15 var ErrGRPCUnhealthy = fmt.Errorf("gRPC application didn't report service healthy") 16 17 // GrpcHealthProbe connects to gRPC application and queries health service for application/service status. 18 type GrpcHealthProbe struct { 19 server string 20 request *hv1.HealthCheckRequest 21 timeout time.Duration 22 dialOptions []grpc.DialOption 23 } 24 25 // NewGrpcHealthProbe constructs GrpcHealthProbe from target string in format 26 // server[/service] 27 // If service is omitted, health of the entire application is probed 28 func NewGrpcHealthProbe(target string, timeout time.Duration, tlsConfig *tls.Config) *GrpcHealthProbe { 29 serverAndService := strings.SplitN(target, "/", 2) 30 31 server := serverAndService[0] 32 request := hv1.HealthCheckRequest{} 33 if len(serverAndService) > 1 { 34 request.Service = serverAndService[1] 35 } 36 37 var dialOptions = []grpc.DialOption{} 38 39 if tlsConfig != nil { 40 dialOptions = append(dialOptions, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig))) 41 } else { 42 dialOptions = append(dialOptions, grpc.WithInsecure()) 43 } 44 45 return &GrpcHealthProbe{ 46 server: server, 47 request: &request, 48 timeout: timeout, 49 dialOptions: dialOptions, 50 } 51 } 52 53 // Check if the target of this GrpcHealthProbe is healthy 54 // If nil is returned, target is healthy, otherwise target is not healthy 55 func (probe *GrpcHealthProbe) Check() error { 56 ctx, cancel := context.WithTimeout(context.Background(), probe.timeout) 57 defer cancel() 58 59 connection, err := grpc.DialContext(ctx, probe.server, probe.dialOptions...) 60 if err != nil { 61 return err 62 } 63 defer connection.Close() 64 65 client := hv1.NewHealthClient(connection) 66 response, err := client.Check(ctx, probe.request) 67 if err != nil { 68 return err 69 } 70 if response == nil || (response != nil && response.Status != hv1.HealthCheckResponse_SERVING) { 71 return ErrGRPCUnhealthy 72 } 73 74 return nil 75 }