pkg/server/healthz.go (75 lines of code) (raw):

package server import ( "context" "fmt" "net" "net/http" "net/url" "os" "time" "github.com/pkg/errors" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/health/grpc_health_v1" "k8s.io/klog/v2" ) const ( readHeaderTimeout = 5 * time.Second ) type HealthZ struct { HealthCheckURL *url.URL UnixSocketPath string RPCTimeout time.Duration } // Serve creates the http handler for serving health requests func (h *HealthZ) Serve() { serveMux := http.NewServeMux() serveMux.HandleFunc(h.HealthCheckURL.EscapedPath(), h.ServeHTTP) server := &http.Server{ Addr: h.HealthCheckURL.Host, ReadHeaderTimeout: readHeaderTimeout, Handler: serveMux, } if err := server.ListenAndServe(); err != nil && errors.Is(err, http.ErrServerClosed) { klog.ErrorS(err, "failed to start health check server") os.Exit(1) } } func (h *HealthZ) ServeHTTP(w http.ResponseWriter, _ *http.Request) { klog.V(5).Infof("Started health check") ctx, cancel := context.WithTimeout(context.Background(), h.RPCTimeout) defer cancel() conn, err := h.dialUnixSocket() if err != nil { http.Error(w, err.Error(), http.StatusServiceUnavailable) return } defer conn.Close() // create the health check grpc client client := grpc_health_v1.NewHealthClient(conn) // check health check response against gRPC endpoint. err = h.checkRPC(ctx, client) if err != nil { http.Error(w, err.Error(), http.StatusServiceUnavailable) return } w.WriteHeader(http.StatusOK) w.Write([]byte("ok")) klog.V(5).Infof("Completed health check") } // checkRPC initiates a grpc request to validate the socket is responding // sends a gRPC HealthCheckRequest and checks if the HealthCheckResponse is valid. func (h *HealthZ) checkRPC(ctx context.Context, client grpc_health_v1.HealthClient) error { v, err := client.Check(ctx, &grpc_health_v1.HealthCheckRequest{}) if err != nil { return err } if v == nil || v.Status != grpc_health_v1.HealthCheckResponse_SERVING { return fmt.Errorf("expected health check response serving") } return nil } func (h *HealthZ) dialUnixSocket() (*grpc.ClientConn, error) { return grpc.Dial( h.UnixSocketPath, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithContextDialer(func(ctx context.Context, target string) (net.Conn, error) { return (&net.Dialer{}).DialContext(ctx, "unix", target) }), ) }