mirror of https://github.com/k3s-io/k3s
Remove global map from healthz
It currently is impossible to use two healthz handlers on different ports in the same process. This removes the global variables in favor of requiring the consumer to specify all health checks up front.pull/6/head
parent
1ce5dda691
commit
015bc3b7bd
|
@ -32,7 +32,6 @@ import (
|
|||
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
||||
nodeControllerPkg "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/controller"
|
||||
replicationControllerPkg "github.com/GoogleCloudPlatform/kubernetes/pkg/controller"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/healthz"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/master/ports"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/resourcequota"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/service"
|
||||
|
|
|
@ -26,12 +26,17 @@ import (
|
|||
"runtime"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/cmd/kube-controller-manager/app"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/healthz"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/version/verflag"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func init() {
|
||||
healthz.DefaultHealthz()
|
||||
}
|
||||
|
||||
func main() {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
s := app.NewCMServer()
|
||||
|
|
|
@ -26,7 +26,6 @@ import (
|
|||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/healthz"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/proxy"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/proxy/config"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
|
|
|
@ -22,12 +22,17 @@ import (
|
|||
"runtime"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/cmd/kube-proxy/app"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/healthz"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/version/verflag"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func init() {
|
||||
healthz.DefaultHealthz()
|
||||
}
|
||||
|
||||
func main() {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
s := app.NewProxyServer()
|
||||
|
|
|
@ -20,97 +20,109 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
// guards names and checks
|
||||
lock = sync.RWMutex{}
|
||||
// used to ensure checks are performed in the order added
|
||||
names = []string{}
|
||||
checks = map[string]*healthzCheck{}
|
||||
)
|
||||
|
||||
func init() {
|
||||
http.HandleFunc("/healthz", handleRootHealthz)
|
||||
// add ping health check by default
|
||||
AddHealthzFunc("ping", func(_ *http.Request) error {
|
||||
return nil
|
||||
})
|
||||
// HealthzChecker is a named healthz check.
|
||||
type HealthzChecker interface {
|
||||
Name() string
|
||||
Check(req *http.Request) error
|
||||
}
|
||||
|
||||
// AddHealthzFunc adds a health check under the url /healhz/{name}
|
||||
func AddHealthzFunc(name string, check func(r *http.Request) error) {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
if _, found := checks[name]; !found {
|
||||
names = append(names, name)
|
||||
}
|
||||
checks[name] = &healthzCheck{name, check}
|
||||
// DefaultHealthz installs the default healthz check to the http.DefaultServeMux.
|
||||
func DefaultHealthz(checks ...HealthzChecker) {
|
||||
InstallHandler(http.DefaultServeMux, checks...)
|
||||
}
|
||||
|
||||
// PingHealthz returns true automatically when checked
|
||||
var PingHealthz HealthzChecker = ping{}
|
||||
|
||||
// ping implements the simplest possible health checker.
|
||||
type ping struct{}
|
||||
|
||||
func (ping) Name() string {
|
||||
return "ping"
|
||||
}
|
||||
|
||||
// PingHealthz is a health check that returns true.
|
||||
func (ping) Check(_ *http.Request) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NamedCheck returns a health checker for the given name and function.
|
||||
func NamedCheck(name string, check func(r *http.Request) error) HealthzChecker {
|
||||
return &healthzCheck{name, check}
|
||||
}
|
||||
|
||||
// InstallHandler registers a handler for health checking on the path "/healthz" to mux.
|
||||
func InstallHandler(mux mux) {
|
||||
lock.RLock()
|
||||
defer lock.RUnlock()
|
||||
mux.HandleFunc("/healthz", handleRootHealthz)
|
||||
func InstallHandler(mux mux, checks ...HealthzChecker) {
|
||||
if len(checks) == 0 {
|
||||
checks = []HealthzChecker{PingHealthz}
|
||||
}
|
||||
mux.Handle("/healthz", handleRootHealthz(checks...))
|
||||
for _, check := range checks {
|
||||
mux.HandleFunc(fmt.Sprintf("/healthz/%v", check.name), adaptCheckToHandler(check.check))
|
||||
mux.Handle(fmt.Sprintf("/healthz/%v", check.Name()), adaptCheckToHandler(check.Check))
|
||||
}
|
||||
}
|
||||
|
||||
// mux is an interface describing the methods InstallHandler requires.
|
||||
type mux interface {
|
||||
HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
|
||||
Handle(pattern string, handler http.Handler)
|
||||
}
|
||||
|
||||
// healthzCheck implements HealthzChecker on an arbitrary name and check function.
|
||||
type healthzCheck struct {
|
||||
name string
|
||||
check func(r *http.Request) error
|
||||
}
|
||||
|
||||
func handleRootHealthz(w http.ResponseWriter, r *http.Request) {
|
||||
lock.RLock()
|
||||
defer lock.RUnlock()
|
||||
failed := false
|
||||
var verboseOut bytes.Buffer
|
||||
for _, name := range names {
|
||||
check, found := checks[name]
|
||||
if !found {
|
||||
// this should not happen
|
||||
http.Error(w, fmt.Sprintf("Internal server error: check \"%q\" not registered", name), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
err := check.check(r)
|
||||
if err != nil {
|
||||
fmt.Fprintf(&verboseOut, "[-]%v failed: %v\n", check.name, err)
|
||||
failed = true
|
||||
} else {
|
||||
fmt.Fprintf(&verboseOut, "[+]%v ok\n", check.name)
|
||||
}
|
||||
}
|
||||
// always be verbose on failure
|
||||
if failed {
|
||||
http.Error(w, fmt.Sprintf("%vhealthz check failed", verboseOut.String()), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
var _ HealthzChecker = &healthzCheck{}
|
||||
|
||||
if _, found := r.URL.Query()["verbose"]; !found {
|
||||
fmt.Fprint(w, "ok")
|
||||
return
|
||||
} else {
|
||||
verboseOut.WriteTo(w)
|
||||
fmt.Fprint(w, "healthz check passed\n")
|
||||
}
|
||||
func (c *healthzCheck) Name() string {
|
||||
return c.name
|
||||
}
|
||||
|
||||
func adaptCheckToHandler(c func(r *http.Request) error) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
func (c *healthzCheck) Check(r *http.Request) error {
|
||||
return c.check(r)
|
||||
}
|
||||
|
||||
// handleRootHealthz returns an http.HandlerFunc that serves the provided checks.
|
||||
func handleRootHealthz(checks ...HealthzChecker) http.HandlerFunc {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
failed := false
|
||||
var verboseOut bytes.Buffer
|
||||
for _, check := range checks {
|
||||
err := check.Check(r)
|
||||
if err != nil {
|
||||
fmt.Fprintf(&verboseOut, "[-]%v failed: %v\n", check.Name(), err)
|
||||
failed = true
|
||||
} else {
|
||||
fmt.Fprintf(&verboseOut, "[+]%v ok\n", check.Name())
|
||||
}
|
||||
}
|
||||
// always be verbose on failure
|
||||
if failed {
|
||||
http.Error(w, fmt.Sprintf("%vhealthz check failed", verboseOut.String()), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if _, found := r.URL.Query()["verbose"]; !found {
|
||||
fmt.Fprint(w, "ok")
|
||||
return
|
||||
}
|
||||
|
||||
verboseOut.WriteTo(w)
|
||||
fmt.Fprint(w, "healthz check passed\n")
|
||||
})
|
||||
}
|
||||
|
||||
// adaptCheckToHandler returns an http.HandlerFunc that serves the provided checks.
|
||||
func adaptCheckToHandler(c func(r *http.Request) error) http.HandlerFunc {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
err := c(r)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Internal server error: %v", err), http.StatusInternalServerError)
|
||||
} else {
|
||||
fmt.Fprint(w, "ok")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -59,12 +59,13 @@ func TestMulitipleChecks(t *testing.T) {
|
|||
|
||||
for i, test := range tests {
|
||||
mux := http.NewServeMux()
|
||||
checks := []HealthzChecker{PingHealthz}
|
||||
if test.addBadCheck {
|
||||
AddHealthzFunc("bad", func(_ *http.Request) error {
|
||||
checks = append(checks, NamedCheck("bad", func(_ *http.Request) error {
|
||||
return errors.New("this will fail")
|
||||
})
|
||||
}))
|
||||
}
|
||||
InstallHandler(mux)
|
||||
InstallHandler(mux, checks...)
|
||||
req, err := http.NewRequest("GET", fmt.Sprintf("http://example.com%v", test.path), nil)
|
||||
if err != nil {
|
||||
t.Fatalf("case[%d] Unexpected error: %v", i, err)
|
||||
|
|
|
@ -110,9 +110,11 @@ func NewServer(host HostInterface, enableDebuggingHandlers bool) Server {
|
|||
|
||||
// InstallDefaultHandlers registers the default set of supported HTTP request patterns with the mux.
|
||||
func (s *Server) InstallDefaultHandlers() {
|
||||
healthz.AddHealthzFunc("docker", s.dockerHealthCheck)
|
||||
healthz.AddHealthzFunc("hostname", s.hostnameHealthCheck)
|
||||
healthz.InstallHandler(s.mux)
|
||||
healthz.InstallHandler(s.mux,
|
||||
healthz.PingHealthz,
|
||||
healthz.NamedCheck("docker", s.dockerHealthCheck),
|
||||
healthz.NamedCheck("hostname", s.hostnameHealthCheck),
|
||||
)
|
||||
s.mux.HandleFunc("/podInfo", s.handlePodInfoOld)
|
||||
s.mux.HandleFunc("/api/v1beta1/podInfo", s.handlePodInfoVersioned)
|
||||
s.mux.HandleFunc("/api/v1beta1/nodeInfo", s.handleNodeInfoVersioned)
|
||||
|
|
|
@ -28,7 +28,6 @@ import (
|
|||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
|
||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/healthz"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/master/ports"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler"
|
||||
|
|
|
@ -19,6 +19,7 @@ package main
|
|||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/healthz"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/version/verflag"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/plugin/cmd/kube-scheduler/app"
|
||||
|
@ -26,6 +27,10 @@ import (
|
|||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func init() {
|
||||
healthz.DefaultHealthz()
|
||||
}
|
||||
|
||||
func main() {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
s := app.NewSchedulerServer()
|
||||
|
|
Loading…
Reference in New Issue