github.com/google/cloudprober@v0.11.3/servers/grpc/grpc.go (about) 1 // Copyright 2018 The Cloudprober Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package grpc provides a simple gRPC server that acts as a probe target. 16 package grpc 17 18 import ( 19 "context" 20 "errors" 21 "fmt" 22 "net" 23 "time" 24 25 "github.com/golang/protobuf/proto" 26 "google.golang.org/grpc" 27 "google.golang.org/grpc/health" 28 "google.golang.org/grpc/reflection" 29 30 "github.com/google/cloudprober/config/runconfig" 31 "github.com/google/cloudprober/logger" 32 "github.com/google/cloudprober/metrics" 33 "github.com/google/cloudprober/probes/probeutils" 34 configpb "github.com/google/cloudprober/servers/grpc/proto" 35 grpcpb "github.com/google/cloudprober/servers/grpc/proto" 36 spb "github.com/google/cloudprober/servers/grpc/proto" 37 healthpb "google.golang.org/grpc/health/grpc_health_v1" 38 ) 39 40 // Server implements a gRPCServer. 41 type Server struct { 42 c *configpb.ServerConf 43 ln net.Listener 44 grpcSrv *grpc.Server 45 healthSrv *health.Server 46 l *logger.Logger 47 startTime time.Time 48 dedicatedSrv bool 49 msg []byte 50 } 51 52 var ( 53 maxMsgSize = 1 * 1024 * 1024 // 1MB 54 msgPattern = []byte("cloudprober") 55 ) 56 57 // Echo reflects back the incoming message. 58 // TODO: return error if EchoMessage is greater than maxMsgSize. 59 func (s *Server) Echo(ctx context.Context, req *spb.EchoMessage) (*spb.EchoMessage, error) { 60 return req, nil 61 } 62 63 // BlobRead returns a blob of data. 64 func (s *Server) BlobRead(ctx context.Context, req *spb.BlobReadRequest) (*spb.BlobReadResponse, error) { 65 reqSize := req.GetSize() 66 if reqSize > int32(maxMsgSize) { 67 return nil, fmt.Errorf("read request size (%d) exceeds max size (%d)", reqSize, maxMsgSize) 68 } 69 return &spb.BlobReadResponse{ 70 Blob: s.msg[0:reqSize], 71 }, nil 72 } 73 74 // ServerStatus returns the current server status. 75 func (s *Server) ServerStatus(ctx context.Context, req *spb.StatusRequest) (*spb.StatusResponse, error) { 76 return &spb.StatusResponse{ 77 UptimeUs: proto.Int64(time.Since(s.startTime).Nanoseconds() / 1000), 78 }, nil 79 } 80 81 // BlobWrite returns the size of blob in the WriteRequest. It does not operate 82 // on the blob. 83 func (s *Server) BlobWrite(ctx context.Context, req *spb.BlobWriteRequest) (*spb.BlobWriteResponse, error) { 84 reqSize := int32(len(req.Blob)) 85 if reqSize > int32(maxMsgSize) { 86 return nil, fmt.Errorf("write request size (%d) exceeds max size (%d)", reqSize, maxMsgSize) 87 } 88 return &spb.BlobWriteResponse{ 89 Size: proto.Int32(reqSize), 90 }, nil 91 } 92 93 // New returns a Server. 94 func New(initCtx context.Context, c *configpb.ServerConf, l *logger.Logger) (*Server, error) { 95 srv := &Server{ 96 c: c, 97 l: l, 98 } 99 srv.msg = make([]byte, maxMsgSize) 100 probeutils.PatternPayload(srv.msg, msgPattern) 101 if c.GetUseDedicatedServer() { 102 if err := srv.newGRPCServer(initCtx); err != nil { 103 return nil, err 104 } 105 srv.dedicatedSrv = true 106 return srv, nil 107 } 108 109 defGRPCSrv := runconfig.DefaultGRPCServer() 110 if defGRPCSrv == nil { 111 return nil, errors.New("initialization of gRPC server failed as default gRPC server is not configured") 112 } 113 l.Warningf("Reusing global gRPC server %v to handle gRPC probes", defGRPCSrv) 114 srv.grpcSrv = defGRPCSrv 115 srv.dedicatedSrv = false 116 srv.startTime = time.Now() 117 grpcpb.RegisterProberServer(defGRPCSrv, srv) 118 return srv, nil 119 } 120 121 func (s *Server) newGRPCServer(ctx context.Context) error { 122 grpcSrv := grpc.NewServer() 123 healthSrv := health.NewServer() 124 ln, err := net.Listen("tcp", fmt.Sprintf(":%d", s.c.GetPort())) 125 if err != nil { 126 return err 127 } 128 // Cleanup listener if ctx is canceled. 129 go func() { 130 <-ctx.Done() 131 ln.Close() 132 }() 133 134 s.ln = ln 135 s.grpcSrv = grpcSrv 136 s.healthSrv = healthSrv 137 s.startTime = time.Now() 138 139 grpcpb.RegisterProberServer(grpcSrv, s) 140 healthpb.RegisterHealthServer(grpcSrv, healthSrv) 141 return nil 142 } 143 144 // Start starts the gRPC server and serves requests until the context is 145 // canceled or the gRPC server panics. 146 func (s *Server) Start(ctx context.Context, dataChan chan<- *metrics.EventMetrics) error { 147 if !s.dedicatedSrv { 148 // Nothing to do as caller owns server. Wait till context is done. 149 <-ctx.Done() 150 return nil 151 } 152 153 s.l.Infof("Starting gRPC server at %s", s.ln.Addr().String()) 154 go func() { 155 <-ctx.Done() 156 s.l.Infof("Context canceled. Shutting down the gRPC server at: %s", s.ln.Addr().String()) 157 for svc := range s.grpcSrv.GetServiceInfo() { 158 s.healthSrv.SetServingStatus(svc, healthpb.HealthCheckResponse_NOT_SERVING) 159 } 160 s.grpcSrv.Stop() 161 }() 162 for si := range s.grpcSrv.GetServiceInfo() { 163 s.healthSrv.SetServingStatus(si, healthpb.HealthCheckResponse_SERVING) 164 } 165 if s.c.GetEnableReflection() { 166 s.l.Infof("Enabling reflection for gRPC server at %s", s.ln.Addr().String()) 167 reflection.Register(s.grpcSrv) 168 } 169 return s.grpcSrv.Serve(s.ln) 170 }