60
vendor/k8s.io/apiserver/pkg/server/healthz/healthz.go
generated
vendored
60
vendor/k8s.io/apiserver/pkg/server/healthz/healthz.go
generated
vendored
@@ -20,6 +20,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -29,8 +30,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/endpoints/metrics"
|
||||
"k8s.io/apiserver/pkg/server/httplog"
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// HealthChecker is a named healthz checker.
|
||||
@@ -82,16 +82,20 @@ func (l *log) Check(_ *http.Request) error {
|
||||
return fmt.Errorf("logging blocked")
|
||||
}
|
||||
|
||||
type cacheSyncWaiter interface {
|
||||
WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool
|
||||
}
|
||||
|
||||
type informerSync struct {
|
||||
sharedInformerFactory informers.SharedInformerFactory
|
||||
cacheSyncWaiter cacheSyncWaiter
|
||||
}
|
||||
|
||||
var _ HealthChecker = &informerSync{}
|
||||
|
||||
// NewInformerSyncHealthz returns a new HealthChecker that will pass only if all informers in the given sharedInformerFactory sync.
|
||||
func NewInformerSyncHealthz(sharedInformerFactory informers.SharedInformerFactory) HealthChecker {
|
||||
// NewInformerSyncHealthz returns a new HealthChecker that will pass only if all informers in the given cacheSyncWaiter sync.
|
||||
func NewInformerSyncHealthz(cacheSyncWaiter cacheSyncWaiter) HealthChecker {
|
||||
return &informerSync{
|
||||
sharedInformerFactory: sharedInformerFactory,
|
||||
cacheSyncWaiter: cacheSyncWaiter,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,8 +108,8 @@ func (i *informerSync) Check(_ *http.Request) error {
|
||||
// Close stopCh to force checking if informers are synced now.
|
||||
close(stopCh)
|
||||
|
||||
var informersByStarted map[bool][]string
|
||||
for informerType, started := range i.sharedInformerFactory.WaitForCacheSync(stopCh) {
|
||||
informersByStarted := make(map[bool][]string)
|
||||
for informerType, started := range i.cacheSyncWaiter.WaitForCacheSync(stopCh) {
|
||||
informersByStarted[started] = append(informersByStarted[started], informerType.String())
|
||||
}
|
||||
|
||||
@@ -157,6 +161,7 @@ func InstallPathHandler(mux mux, path string, checks ...HealthChecker) {
|
||||
|
||||
klog.V(5).Infof("Installing health checkers for (%v): %v", path, formatQuoted(checkerNames(checks...)...))
|
||||
|
||||
name := strings.Split(strings.TrimPrefix(path, "/"), "/")[0]
|
||||
mux.Handle(path,
|
||||
metrics.InstrumentHandlerFunc("GET",
|
||||
/* group = */ "",
|
||||
@@ -165,7 +170,9 @@ func InstallPathHandler(mux mux, path string, checks ...HealthChecker) {
|
||||
/* subresource = */ path,
|
||||
/* scope = */ "",
|
||||
/* component = */ "",
|
||||
handleRootHealthz(checks...)))
|
||||
/* deprecated */ false,
|
||||
/* removedRelease */ "",
|
||||
handleRootHealth(name, checks...)))
|
||||
for _, check := range checks {
|
||||
mux.Handle(fmt.Sprintf("%s/%v", path, check.Name()), adaptCheckToHandler(check.Check))
|
||||
}
|
||||
@@ -201,38 +208,41 @@ func getExcludedChecks(r *http.Request) sets.String {
|
||||
return sets.NewString()
|
||||
}
|
||||
|
||||
// handleRootHealthz returns an http.HandlerFunc that serves the provided checks.
|
||||
func handleRootHealthz(checks ...HealthChecker) http.HandlerFunc {
|
||||
// handleRootHealth returns an http.HandlerFunc that serves the provided checks.
|
||||
func handleRootHealth(name string, checks ...HealthChecker) http.HandlerFunc {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
failed := false
|
||||
excluded := getExcludedChecks(r)
|
||||
var verboseOut bytes.Buffer
|
||||
// failedVerboseLogOutput is for output to the log. It indicates detailed failed output information for the log.
|
||||
var failedVerboseLogOutput bytes.Buffer
|
||||
var failedChecks []string
|
||||
var individualCheckOutput bytes.Buffer
|
||||
for _, check := range checks {
|
||||
// no-op the check if we've specified we want to exclude the check
|
||||
if excluded.Has(check.Name()) {
|
||||
excluded.Delete(check.Name())
|
||||
fmt.Fprintf(&verboseOut, "[+]%v excluded: ok\n", check.Name())
|
||||
fmt.Fprintf(&individualCheckOutput, "[+]%s excluded: ok\n", check.Name())
|
||||
continue
|
||||
}
|
||||
if err := check.Check(r); err != nil {
|
||||
// don't include the error since this endpoint is public. If someone wants more detail
|
||||
// they should have explicit permission to the detailed checks.
|
||||
klog.V(4).Infof("healthz check %v failed: %v", check.Name(), err)
|
||||
fmt.Fprintf(&verboseOut, "[-]%v failed: reason withheld\n", check.Name())
|
||||
failed = true
|
||||
fmt.Fprintf(&individualCheckOutput, "[-]%s failed: reason withheld\n", check.Name())
|
||||
// but we do want detailed information for our log
|
||||
fmt.Fprintf(&failedVerboseLogOutput, "[-]%s failed: %v\n", check.Name(), err)
|
||||
failedChecks = append(failedChecks, check.Name())
|
||||
} else {
|
||||
fmt.Fprintf(&verboseOut, "[+]%v ok\n", check.Name())
|
||||
fmt.Fprintf(&individualCheckOutput, "[+]%s ok\n", check.Name())
|
||||
}
|
||||
}
|
||||
if excluded.Len() > 0 {
|
||||
fmt.Fprintf(&verboseOut, "warn: some health checks cannot be excluded: no matches for %v\n", formatQuoted(excluded.List()...))
|
||||
klog.Warningf("cannot exclude some health checks, no health checks are installed matching %v",
|
||||
fmt.Fprintf(&individualCheckOutput, "warn: some health checks cannot be excluded: no matches for %s\n", formatQuoted(excluded.List()...))
|
||||
klog.Warningf("cannot exclude some health checks, no health checks are installed matching %s",
|
||||
formatQuoted(excluded.List()...))
|
||||
}
|
||||
// always be verbose on failure
|
||||
if failed {
|
||||
klog.V(2).Infof("%vhealthz check failed", verboseOut.String())
|
||||
http.Error(httplog.Unlogged(r, w), fmt.Sprintf("%vhealthz check failed", verboseOut.String()), http.StatusInternalServerError)
|
||||
if len(failedChecks) > 0 {
|
||||
klog.V(2).Infof("%s check failed: %s\n%v", strings.Join(failedChecks, ","), name, failedVerboseLogOutput.String())
|
||||
http.Error(httplog.Unlogged(r, w), fmt.Sprintf("%s%s check failed", individualCheckOutput.String(), name), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -243,8 +253,8 @@ func handleRootHealthz(checks ...HealthChecker) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
verboseOut.WriteTo(w)
|
||||
fmt.Fprint(w, "healthz check passed\n")
|
||||
individualCheckOutput.WriteTo(w)
|
||||
fmt.Fprintf(w, "%s check passed\n", name)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user