-
Notifications
You must be signed in to change notification settings - Fork 278
/
health.go
95 lines (84 loc) · 3.1 KB
/
health.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
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/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 {
state := server.UnknownOperationalState
if v := w.operationalState.Load(); !util.IsNil(v) {
state = v.(server.OperationalState)
}
healthInfo := &pbhealth.HealthInfo{
State: state.String(),
}
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
}