-
Notifications
You must be signed in to change notification settings - Fork 2.8k
/
kube_proxy_healthz.go
91 lines (78 loc) · 2.66 KB
/
kube_proxy_healthz.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
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium
package cmd
import (
"context"
"errors"
"fmt"
"net"
"net/http"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
"github.com/cilium/cilium/api/v1/models"
"github.com/cilium/cilium/pkg/time"
)
// DaemonInterface to help with testing.
type DaemonInterface interface {
getStatus(bool) models.StatusResponse
}
// ServiceInterface to help with testing.
type ServiceInterface interface {
GetLastUpdatedTs() time.Time
GetCurrentTs() time.Time
}
type kubeproxyHealthzHandler struct {
d DaemonInterface
svc ServiceInterface
}
// startKubeProxyHealthzHTTPService registers a handler function for the kube-proxy /healthz
// status HTTP endpoint exposed on addr.
// This endpoint reports the agent health status with the timestamp.
func (d *Daemon) startKubeProxyHealthzHTTPService(addr string) {
lc := net.ListenConfig{Control: setsockoptReuseAddrAndPort}
ln, err := lc.Listen(context.Background(), "tcp", addr)
addrField := logrus.Fields{"address": addr}
if errors.Is(err, unix.EADDRNOTAVAIL) {
log.WithFields(addrField).Info("KubeProxy healthz server not available")
} else if err != nil {
log.WithFields(addrField).WithError(err).Fatal("hint: kube-proxy should not be running nor listening on the same healthz-bind-address.")
}
mux := http.NewServeMux()
mux.Handle("/healthz", kubeproxyHealthzHandler{d: d, svc: d.svc})
srv := &http.Server{
Addr: addr,
Handler: mux,
}
go func() {
err := srv.Serve(ln)
if errors.Is(err, http.ErrServerClosed) {
log.WithFields(addrField).Info("kube-proxy healthz status API server shutdown")
} else if err != nil {
log.WithFields(addrField).WithError(err).Fatal("Unable to start kube-proxy healthz server")
}
}()
log.WithFields(addrField).Info("Started kube-proxy healthz server")
}
func (h kubeproxyHealthzHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
isUnhealthy := func(sr *models.StatusResponse) bool {
if sr.Cilium != nil {
state := sr.Cilium.State
return state != models.StatusStateOk && state != models.StatusStateDisabled
}
return false
}
statusCode := http.StatusOK
currentTs := h.svc.GetCurrentTs()
var lastUpdateTs = currentTs
// We piggy back here on Cilium daemon health. If Cilium is healthy, we can
// reasonably assume that the node networking is ready.
sr := h.d.getStatus(true)
if isUnhealthy(&sr) {
statusCode = http.StatusServiceUnavailable
lastUpdateTs = h.svc.GetLastUpdatedTs()
}
w.Header().Set("Content-Type", "application/json")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.WriteHeader(statusCode)
fmt.Fprintf(w, `{"lastUpdated": %q,"currentTime": %q}`, lastUpdateTs, currentTs)
}