mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 21:47:07 +00:00
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.
This commit is contained in:
parent
1ce5dda691
commit
015bc3b7bd
@ -32,7 +32,6 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
||||||
nodeControllerPkg "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/controller"
|
nodeControllerPkg "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider/controller"
|
||||||
replicationControllerPkg "github.com/GoogleCloudPlatform/kubernetes/pkg/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/master/ports"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/resourcequota"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/resourcequota"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/service"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/service"
|
||||||
|
@ -26,12 +26,17 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/cmd/kube-controller-manager/app"
|
"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/util"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/version/verflag"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/version/verflag"
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
healthz.DefaultHealthz()
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
s := app.NewCMServer()
|
s := app.NewCMServer()
|
||||||
|
@ -26,7 +26,6 @@ import (
|
|||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/healthz"
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/proxy"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/proxy"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/proxy/config"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/proxy/config"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
|
@ -22,12 +22,17 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/cmd/kube-proxy/app"
|
"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/util"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/version/verflag"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/version/verflag"
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
healthz.DefaultHealthz()
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
s := app.NewProxyServer()
|
s := app.NewProxyServer()
|
||||||
|
@ -20,73 +20,83 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// HealthzChecker is a named healthz check.
|
||||||
// guards names and checks
|
type HealthzChecker interface {
|
||||||
lock = sync.RWMutex{}
|
Name() string
|
||||||
// used to ensure checks are performed in the order added
|
Check(req *http.Request) error
|
||||||
names = []string{}
|
}
|
||||||
checks = map[string]*healthzCheck{}
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
// DefaultHealthz installs the default healthz check to the http.DefaultServeMux.
|
||||||
http.HandleFunc("/healthz", handleRootHealthz)
|
func DefaultHealthz(checks ...HealthzChecker) {
|
||||||
// add ping health check by default
|
InstallHandler(http.DefaultServeMux, checks...)
|
||||||
AddHealthzFunc("ping", func(_ *http.Request) error {
|
}
|
||||||
|
|
||||||
|
// 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
|
return nil
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddHealthzFunc adds a health check under the url /healhz/{name}
|
// NamedCheck returns a health checker for the given name and function.
|
||||||
func AddHealthzFunc(name string, check func(r *http.Request) error) {
|
func NamedCheck(name string, check func(r *http.Request) error) HealthzChecker {
|
||||||
lock.Lock()
|
return &healthzCheck{name, check}
|
||||||
defer lock.Unlock()
|
|
||||||
if _, found := checks[name]; !found {
|
|
||||||
names = append(names, name)
|
|
||||||
}
|
|
||||||
checks[name] = &healthzCheck{name, check}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstallHandler registers a handler for health checking on the path "/healthz" to mux.
|
// InstallHandler registers a handler for health checking on the path "/healthz" to mux.
|
||||||
func InstallHandler(mux mux) {
|
func InstallHandler(mux mux, checks ...HealthzChecker) {
|
||||||
lock.RLock()
|
if len(checks) == 0 {
|
||||||
defer lock.RUnlock()
|
checks = []HealthzChecker{PingHealthz}
|
||||||
mux.HandleFunc("/healthz", handleRootHealthz)
|
}
|
||||||
|
mux.Handle("/healthz", handleRootHealthz(checks...))
|
||||||
for _, check := range 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.
|
// mux is an interface describing the methods InstallHandler requires.
|
||||||
type mux interface {
|
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 {
|
type healthzCheck struct {
|
||||||
name string
|
name string
|
||||||
check func(r *http.Request) error
|
check func(r *http.Request) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleRootHealthz(w http.ResponseWriter, r *http.Request) {
|
var _ HealthzChecker = &healthzCheck{}
|
||||||
lock.RLock()
|
|
||||||
defer lock.RUnlock()
|
func (c *healthzCheck) Name() string {
|
||||||
|
return c.name
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
failed := false
|
||||||
var verboseOut bytes.Buffer
|
var verboseOut bytes.Buffer
|
||||||
for _, name := range names {
|
for _, check := range checks {
|
||||||
check, found := checks[name]
|
err := check.Check(r)
|
||||||
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 {
|
if err != nil {
|
||||||
fmt.Fprintf(&verboseOut, "[-]%v failed: %v\n", check.name, err)
|
fmt.Fprintf(&verboseOut, "[-]%v failed: %v\n", check.Name(), err)
|
||||||
failed = true
|
failed = true
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(&verboseOut, "[+]%v ok\n", check.name)
|
fmt.Fprintf(&verboseOut, "[+]%v ok\n", check.Name())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// always be verbose on failure
|
// always be verbose on failure
|
||||||
@ -98,19 +108,21 @@ func handleRootHealthz(w http.ResponseWriter, r *http.Request) {
|
|||||||
if _, found := r.URL.Query()["verbose"]; !found {
|
if _, found := r.URL.Query()["verbose"]; !found {
|
||||||
fmt.Fprint(w, "ok")
|
fmt.Fprint(w, "ok")
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
verboseOut.WriteTo(w)
|
|
||||||
fmt.Fprint(w, "healthz check passed\n")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func adaptCheckToHandler(c func(r *http.Request) error) func(w http.ResponseWriter, r *http.Request) {
|
verboseOut.WriteTo(w)
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
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)
|
err := c(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, fmt.Sprintf("Internal server error: %v", err), http.StatusInternalServerError)
|
http.Error(w, fmt.Sprintf("Internal server error: %v", err), http.StatusInternalServerError)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprint(w, "ok")
|
fmt.Fprint(w, "ok")
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
@ -59,12 +59,13 @@ func TestMulitipleChecks(t *testing.T) {
|
|||||||
|
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
checks := []HealthzChecker{PingHealthz}
|
||||||
if test.addBadCheck {
|
if test.addBadCheck {
|
||||||
AddHealthzFunc("bad", func(_ *http.Request) error {
|
checks = append(checks, NamedCheck("bad", func(_ *http.Request) error {
|
||||||
return errors.New("this will fail")
|
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)
|
req, err := http.NewRequest("GET", fmt.Sprintf("http://example.com%v", test.path), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("case[%d] Unexpected error: %v", i, err)
|
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.
|
// InstallDefaultHandlers registers the default set of supported HTTP request patterns with the mux.
|
||||||
func (s *Server) InstallDefaultHandlers() {
|
func (s *Server) InstallDefaultHandlers() {
|
||||||
healthz.AddHealthzFunc("docker", s.dockerHealthCheck)
|
healthz.InstallHandler(s.mux,
|
||||||
healthz.AddHealthzFunc("hostname", s.hostnameHealthCheck)
|
healthz.PingHealthz,
|
||||||
healthz.InstallHandler(s.mux)
|
healthz.NamedCheck("docker", s.dockerHealthCheck),
|
||||||
|
healthz.NamedCheck("hostname", s.hostnameHealthCheck),
|
||||||
|
)
|
||||||
s.mux.HandleFunc("/podInfo", s.handlePodInfoOld)
|
s.mux.HandleFunc("/podInfo", s.handlePodInfoOld)
|
||||||
s.mux.HandleFunc("/api/v1beta1/podInfo", s.handlePodInfoVersioned)
|
s.mux.HandleFunc("/api/v1beta1/podInfo", s.handlePodInfoVersioned)
|
||||||
s.mux.HandleFunc("/api/v1beta1/nodeInfo", s.handleNodeInfoVersioned)
|
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"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
|
"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/master/ports"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler"
|
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler"
|
||||||
|
@ -19,6 +19,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/healthz"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/version/verflag"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/version/verflag"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/plugin/cmd/kube-scheduler/app"
|
"github.com/GoogleCloudPlatform/kubernetes/plugin/cmd/kube-scheduler/app"
|
||||||
@ -26,6 +27,10 @@ import (
|
|||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
healthz.DefaultHealthz()
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
s := app.NewSchedulerServer()
|
s := app.NewSchedulerServer()
|
||||||
|
Loading…
Reference in New Issue
Block a user