diff --git a/plugin/health/health.go b/plugin/health/health.go index c69b221ec..980cf2bc8 100644 --- a/plugin/health/health.go +++ b/plugin/health/health.go @@ -6,6 +6,7 @@ import ( "io" "net" "net/http" + "net/url" "time" clog "github.com/coredns/coredns/plugin/pkg/log" @@ -16,8 +17,9 @@ var log = clog.NewWithPlugin("health") // Health implements healthchecks by exporting a HTTP endpoint. type health struct { - Addr string - lameduck time.Duration + Addr string + lameduck time.Duration + healthURI *url.URL ln net.Listener nlSetup bool @@ -30,6 +32,19 @@ func (h *health) OnStartup() error { if h.Addr == "" { h.Addr = ":8080" } + + var err error + h.healthURI, err = url.Parse("http://" + h.Addr) + if err != nil { + return err + } + + h.healthURI.Path = "/health" + if h.healthURI.Host == "" { + // while we can listen on multiple network interfaces, we need to pick one to poll + h.healthURI.Host = "localhost" + } + ln, err := reuseport.Listen("tcp", h.Addr) if err != nil { return err @@ -39,7 +54,7 @@ func (h *health) OnStartup() error { h.mux = http.NewServeMux() h.nlSetup = true - h.mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { + h.mux.HandleFunc(h.healthURI.Path, func(w http.ResponseWriter, r *http.Request) { // We're always healthy. w.WriteHeader(http.StatusOK) io.WriteString(w, http.StatusText(http.StatusOK)) diff --git a/plugin/health/overloaded.go b/plugin/health/overloaded.go index 57b9ca2d0..160f90f02 100644 --- a/plugin/health/overloaded.go +++ b/plugin/health/overloaded.go @@ -32,8 +32,7 @@ func (h *health) overloaded(ctx context.Context) { Transport: bypassProxy, } - url := "http://" + h.Addr + "/health" - req, _ := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + req, _ := http.NewRequestWithContext(ctx, http.MethodGet, h.healthURI.String(), nil) tick := time.NewTicker(1 * time.Second) defer tick.Stop() @@ -49,14 +48,14 @@ func (h *health) overloaded(ctx context.Context) { if err != nil { HealthDuration.Observe(time.Since(start).Seconds()) HealthFailures.Inc() - log.Warningf("Local health request to %q failed: %s", url, err) + log.Warningf("Local health request to %q failed: %s", req.URL.String(), err) continue } resp.Body.Close() elapsed := time.Since(start) HealthDuration.Observe(elapsed.Seconds()) if elapsed > time.Second { // 1s is pretty random, but a *local* scrape taking that long isn't good - log.Warningf("Local health request to %q took more than 1s: %s", url, elapsed) + log.Warningf("Local health request to %q took more than 1s: %s", req.URL.String(), elapsed) } case <-ctx.Done(): diff --git a/plugin/health/overloaded_test.go b/plugin/health/overloaded_test.go index c927f13b2..da40a4e7b 100644 --- a/plugin/health/overloaded_test.go +++ b/plugin/health/overloaded_test.go @@ -4,6 +4,7 @@ import ( "context" "net/http" "net/http/httptest" + "net/url" "testing" "time" ) @@ -22,6 +23,13 @@ func Test_health_overloaded_cancellation(t *testing.T) { stop: cancel, } + var err error + h.healthURI, err = url.Parse(ts.URL) + if err != nil { + t.Fatal(err) + } + h.healthURI.Path = "/health" + stopped := make(chan struct{}) go func() { h.overloaded(ctx)