Files
threshold/internal/daemon/worker/health.go
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

103 lines
3.4 KiB
Go
Raw Normal View History

2022-09-19 11:24:42 -07:00
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
2023-02-02 17:15:17 -08:00
2022-09-19 11:24:42 -07:00
package worker
import (
"context"
"fmt"
"net/http"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/hashicorp/boundary/internal/daemon/worker/session"
opsservices "github.com/hashicorp/boundary/internal/gen/ops/services"
pbhealth "github.com/hashicorp/boundary/internal/gen/worker/health"
"github.com/hashicorp/boundary/internal/server"
"github.com/hashicorp/boundary/internal/util"
"google.golang.org/grpc/connectivity"
2022-09-19 11:24:42 -07:00
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/types/known/wrapperspb"
)
var healthCheckMarshaler = &runtime.JSONPb{
MarshalOptions: protojson.MarshalOptions{
// Ensures the json marshaler uses the snake casing as defined in the proto field names.
UseProtoNames: true,
// Do not add fields set to zero value to json.
EmitUnpopulated: false,
},
UnmarshalOptions: protojson.UnmarshalOptions{
// Allows requests to contain unknown fields.
DiscardUnknown: true,
},
}
// workerHealthServer is the HealthServer for the worker process. This server
// will always return a 200.
type workerHealthServer struct {
worker *Worker
opsservices.UnimplementedHealthServiceServer
}
// GetHealth satisfies the opsservices.HealthServiceServer interface.
// This implementation will always return 200.
func (w workerHealthServer) GetHealth(ctx context.Context, req *opsservices.GetHealthRequest) (*opsservices.GetHealthResponse, error) {
resp := &opsservices.GetHealthResponse{}
if req.GetWorkerInfo() {
resp.WorkerProcessInfo = w.worker.HealthInformation()
}
return resp, nil
}
// HealthInformation returns the current worker process health information.
func (w *Worker) HealthInformation() *pbhealth.HealthInfo {
operationalState := server.UnknownOperationalState
2022-09-19 11:24:42 -07:00
if v := w.operationalState.Load(); !util.IsNil(v) {
operationalState = v.(server.OperationalState)
2022-09-19 11:24:42 -07:00
}
var upstreamConnectionState connectivity.State
if v := w.upstreamConnectionState.Load(); !util.IsNil(v) {
upstreamConnectionState = v.(connectivity.State)
}
2022-09-19 11:24:42 -07:00
healthInfo := &pbhealth.HealthInfo{
State: operationalState.String(),
UpstreamConnectionState: upstreamConnectionState.String(),
2022-09-19 11:24:42 -07:00
}
if w.sessionManager == nil {
// This is assigned in worker Start() which is called prior to the ops
// listener so this should always be set. This check is here just to
// be safe in case that changes.
return healthInfo
}
sessionConns := make(map[string]uint32)
w.sessionManager.ForEachLocalSession(
func(s session.Session) bool {
if connCount := len(s.GetLocalConnections()); connCount > 0 {
sessionConns[s.GetId()] = uint32(connCount)
}
return true
})
healthInfo.ActiveSessionCount = wrapperspb.UInt32(uint32(len(sessionConns)))
healthInfo.SessionConnections = sessionConns
return healthInfo
}
// GetHealthHandler returns an http.Handler that can be used for handling
// health check requests for just the worker.
func (w *Worker) GetHealthHandler() (http.Handler, error) {
const op = "worker.(Worker).GetHealthHandler"
mux := runtime.NewServeMux(
runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.HTTPBodyMarshaler{
Marshaler: healthCheckMarshaler,
}))
err := opsservices.RegisterHealthServiceHandlerServer(w.baseContext, mux, workerHealthServer{worker: w})
if err != nil {
return nil, fmt.Errorf("%s: failed to register health service handler: %w", op, err)
}
return mux, nil
}