From 253ebffe784f017c4bcdc55538b5c78a73e2f873 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Thu, 23 Apr 2015 11:53:31 -0700 Subject: [PATCH] http: adding sys/health endpoint --- http/handler.go | 1 + http/sys_health.go | 60 +++++++++++++++++++++++++++++++++++++++++ http/sys_health_test.go | 32 ++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 http/sys_health.go create mode 100644 http/sys_health_test.go diff --git a/http/handler.go b/http/handler.go index 3af249b5ed..a73f9db9f0 100644 --- a/http/handler.go +++ b/http/handler.go @@ -34,6 +34,7 @@ func Handler(core *vault.Core) http.Handler { mux.Handle("/v1/sys/audit", handleSysListAudit(core)) mux.Handle("/v1/sys/audit/", handleSysAudit(core)) mux.Handle("/v1/sys/leader", handleSysLeader(core)) + mux.Handle("/v1/sys/health", handleSysHealth(core)) mux.Handle("/v1/", handleLogical(core)) // Wrap the handler in another handler to trigger all help paths. diff --git a/http/sys_health.go b/http/sys_health.go new file mode 100644 index 0000000000..8a53d1889d --- /dev/null +++ b/http/sys_health.go @@ -0,0 +1,60 @@ +package http + +import ( + "encoding/json" + "net/http" + + "github.com/hashicorp/vault/vault" +) + +func handleSysHealth(core *vault.Core) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case "GET": + handleSysHealthGet(core, w, r) + default: + respondError(w, http.StatusMethodNotAllowed, nil) + } + }) +} + +func handleSysHealthGet(core *vault.Core, w http.ResponseWriter, r *http.Request) { + // Check system status + sealed, _ := core.Sealed() + standby, _ := core.Standby() + init, err := core.Initialized() + if err != nil { + respondError(w, http.StatusInternalServerError, err) + return + } + + // Determine the status code + code := http.StatusOK + switch { + case !init: + code = http.StatusInternalServerError + case sealed: + code = http.StatusInternalServerError + case standby: + code = 429 // Consul warning code + } + + // Format the body + body := &HealthResponse{ + Initialized: init, + Sealed: sealed, + Standby: standby, + } + + // Generate the response + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(code) + enc := json.NewEncoder(w) + enc.Encode(body) +} + +type HealthResponse struct { + Initialized bool `json:"initialized"` + Sealed bool `json:"sealed"` + Standby bool `json:"standby"` +} diff --git a/http/sys_health_test.go b/http/sys_health_test.go new file mode 100644 index 0000000000..db9f8e1e4f --- /dev/null +++ b/http/sys_health_test.go @@ -0,0 +1,32 @@ +package http + +import ( + "net/http" + "reflect" + "testing" + + "github.com/hashicorp/vault/vault" +) + +func TestSysHealth_get(t *testing.T) { + core, _, _ := vault.TestCoreUnsealed(t) + ln, addr := TestServer(t, core) + defer ln.Close() + + resp, err := http.Get(addr + "/v1/sys/health") + if err != nil { + t.Fatalf("err: %s", err) + } + + var actual map[string]interface{} + expected := map[string]interface{}{ + "initialized": true, + "sealed": false, + "standby": false, + } + testResponseStatus(t, resp, 200) + testResponseBody(t, resp, &actual) + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("bad: %#v", actual) + } +}