Remove the word middleware (#1067)

* Rename middleware to plugin

first pass; mostly used 'sed', few spots where I manually changed
text.

This still builds a coredns binary.

* fmt error

* Rename AddMiddleware to AddPlugin

* Readd AddMiddleware to remain backwards compat
This commit is contained in:
Miek Gieben
2017-09-14 09:36:06 +01:00
committed by GitHub
parent b984aa4559
commit d8714e64e4
354 changed files with 974 additions and 969 deletions

23
plugin/health/README.md Normal file
View File

@@ -0,0 +1,23 @@
# health
This module enables a simple health check endpoint. By default it will listen on port 8080.
## Syntax
~~~
health [ADDRESS]
~~~
Optionally takes an address; the default is `:8080`. The health path is fixed to `/health`. The
health endpoint returns a 200 response code and the word "OK" when CoreDNS is healthy. It returns
a 503. *health* periodically (1s) polls plugin that exports health information. If any of the
plugin signals that it is unhealthy, the server will go unhealthy too. Each plugin that
supports health checks has a section "Health" in their README.
## Examples
Run another health endpoint on http://localhost:8091.
~~~
health localhost:8091
~~~

69
plugin/health/health.go Normal file
View File

@@ -0,0 +1,69 @@
// Package health implements an HTTP handler that responds to health checks.
package health
import (
"io"
"log"
"net"
"net/http"
"sync"
)
var once sync.Once
type health struct {
Addr string
ln net.Listener
mux *http.ServeMux
// A slice of Healthers that the health plugin will poll every second for their health status.
h []Healther
sync.RWMutex
ok bool // ok is the global boolean indicating an all healthy plugin stack
}
func (h *health) Startup() error {
if h.Addr == "" {
h.Addr = defAddr
}
once.Do(func() {
ln, err := net.Listen("tcp", h.Addr)
if err != nil {
log.Printf("[ERROR] Failed to start health handler: %s", err)
return
}
h.ln = ln
h.mux = http.NewServeMux()
h.mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
if h.Ok() {
w.WriteHeader(http.StatusOK)
io.WriteString(w, ok)
return
}
w.WriteHeader(http.StatusServiceUnavailable)
})
go func() {
http.Serve(h.ln, h.mux)
}()
})
return nil
}
func (h *health) Shutdown() error {
if h.ln != nil {
return h.ln.Close()
}
return nil
}
const (
ok = "OK"
defAddr = ":8080"
path = "/health"
)

View File

@@ -0,0 +1,47 @@
package health
// TODO(miek): enable again if plugin gets health check.
/*
func TestHealth(t *testing.T) {
h := health{Addr: ":0"}
h.h = append(h.h, &erratic.Erratic{})
if err := h.Startup(); err != nil {
t.Fatalf("Unable to startup the health server: %v", err)
}
defer h.Shutdown()
// Reconstruct the http address based on the port allocated by operating system.
address := fmt.Sprintf("http://%s%s", h.ln.Addr().String(), path)
// Norhing set should be unhealthy
response, err := http.Get(address)
if err != nil {
t.Fatalf("Unable to query %s: %v", address, err)
}
if response.StatusCode != 503 {
t.Errorf("Invalid status code: expecting '503', got '%d'", response.StatusCode)
}
response.Body.Close()
// Make healthy
h.Poll()
response, err = http.Get(address)
if err != nil {
t.Fatalf("Unable to query %s: %v", address, err)
}
if response.StatusCode != 200 {
t.Errorf("Invalid status code: expecting '200', got '%d'", response.StatusCode)
}
content, err := ioutil.ReadAll(response.Body)
if err != nil {
t.Fatalf("Unable to get response body from %s: %v", address, err)
}
response.Body.Close()
if string(content) != ok {
t.Errorf("Invalid response body: expecting 'OK', got '%s'", string(content))
}
}
*/

42
plugin/health/healther.go Normal file
View File

@@ -0,0 +1,42 @@
package health
// Healther interface needs to be implemented by each plugin willing to
// provide healthhceck information to the health plugin. As a second step
// the plugin needs to registered against the health plugin, by addding
// it to healthers map. Note this method should return quickly, i.e. just
// checking a boolean status, as it is called every second from the health
// plugin.
type Healther interface {
// Health returns a boolean indicating the health status of a plugin.
// False indicates unhealthy.
Health() bool
}
// Ok returns the global health status of all plugin configured in this server.
func (h *health) Ok() bool {
h.RLock()
defer h.RUnlock()
return h.ok
}
// SetOk sets the global health status of all plugin configured in this server.
func (h *health) SetOk(ok bool) {
h.Lock()
defer h.Unlock()
h.ok = ok
}
// poll polls all healthers and sets the global state.
func (h *health) poll() {
for _, m := range h.h {
if !m.Health() {
h.SetOk(false)
return
}
}
h.SetOk(true)
}
// Middleware that implements the Healther interface.
// TODO(miek): none yet.
var healthers = map[string]bool{}

73
plugin/health/setup.go Normal file
View File

@@ -0,0 +1,73 @@
package health
import (
"net"
"time"
"github.com/coredns/coredns/core/dnsserver"
"github.com/coredns/coredns/plugin"
"github.com/mholt/caddy"
)
func init() {
caddy.RegisterPlugin("health", caddy.Plugin{
ServerType: "dns",
Action: setup,
})
}
func setup(c *caddy.Controller) error {
addr, err := healthParse(c)
if err != nil {
return plugin.Error("health", err)
}
h := &health{Addr: addr}
c.OnStartup(func() error {
for he := range healthers {
m := dnsserver.GetConfig(c).Handler(he)
if x, ok := m.(Healther); ok {
h.h = append(h.h, x)
}
}
return nil
})
c.OnStartup(func() error {
h.poll()
go func() {
for {
<-time.After(1 * time.Second)
h.poll()
}
}()
return nil
})
c.OnStartup(h.Startup)
c.OnFinalShutdown(h.Shutdown)
// Don't do AddMiddleware, as health is not *really* a plugin just a separate webserver running.
return nil
}
func healthParse(c *caddy.Controller) (string, error) {
addr := ""
for c.Next() {
args := c.RemainingArgs()
switch len(args) {
case 0:
case 1:
addr = args[0]
if _, _, e := net.SplitHostPort(addr); e != nil {
return "", e
}
default:
return "", c.ArgErr()
}
}
return addr, nil
}

View File

@@ -0,0 +1,35 @@
package health
import (
"testing"
"github.com/mholt/caddy"
)
func TestSetupHealth(t *testing.T) {
tests := []struct {
input string
shouldErr bool
}{
{`health`, false},
{`health localhost:1234`, false},
{`health bla:a`, false},
{`health bla`, true},
{`health bla bla`, true},
}
for i, test := range tests {
c := caddy.NewTestController("dns", test.input)
_, err := healthParse(c)
if test.shouldErr && err == nil {
t.Errorf("Test %d: Expected error but found %s for input %s", i, err, test.input)
}
if err != nil {
if !test.shouldErr {
t.Errorf("Test %d: Expected no error but found one for input %s. Error was: %v", i, test.input, err)
}
}
}
}