diff --git a/http/sys_health.go b/http/sys_health.go index bde39a28e2..73b85688c5 100644 --- a/http/sys_health.go +++ b/http/sys_health.go @@ -3,6 +3,7 @@ package http import ( "encoding/json" "net/http" + "strconv" "time" "github.com/hashicorp/vault/vault" @@ -20,9 +21,56 @@ func handleSysHealth(core *vault.Core) http.Handler { } func handleSysHealthGet(core *vault.Core, w http.ResponseWriter, r *http.Request) { + // Check if being a standby is allowed for the purpose of a 200 OK _, standbyOK := r.URL.Query()["standbyok"] + // FIXME: Change the sealed code to http.StatusServiceUnavailable at some + // point + sealedCode := http.StatusInternalServerError + standbyCode := http.StatusTooManyRequests // Consul warning code + activeCode := http.StatusOK + + var err error + sealedCodeStr, sealedCodeOk := r.URL.Query()["sealedcode"] + if sealedCodeOk { + if len(sealedCodeStr) < 1 { + respondError(w, http.StatusBadRequest, nil) + return + } + sealedCode, err = strconv.Atoi(sealedCodeStr[0]) + if err != nil { + respondError(w, http.StatusBadRequest, nil) + return + } + } + standbyCodeStr, standbyCodeOk := r.URL.Query()["standbycode"] + if standbyCodeOk { + if len(standbyCodeStr) < 1 { + respondError(w, http.StatusBadRequest, nil) + return + } + standbyCode, err = strconv.Atoi(standbyCodeStr[0]) + if err != nil { + respondError(w, http.StatusBadRequest, nil) + return + } + } + + activeCodeStr, activeCodeOk := r.URL.Query()["activecode"] + if activeCodeOk { + if len(activeCodeStr) < 1 { + respondError(w, http.StatusBadRequest, nil) + return + } + + activeCode, err = strconv.Atoi(activeCodeStr[0]) + if err != nil { + respondError(w, http.StatusBadRequest, nil) + return + } + } + // Check system status sealed, _ := core.Sealed() standby, _ := core.Standby() @@ -33,14 +81,14 @@ func handleSysHealthGet(core *vault.Core, w http.ResponseWriter, r *http.Request } // Determine the status code - code := http.StatusOK + code := activeCode switch { case !init: code = http.StatusInternalServerError case sealed: - code = http.StatusInternalServerError + code = sealedCode case !standbyOK && standby: - code = 429 // Consul warning code + code = standbyCode } // Format the body diff --git a/http/sys_health_test.go b/http/sys_health_test.go index 6e50e91dd4..03b5f207ac 100644 --- a/http/sys_health_test.go +++ b/http/sys_health_test.go @@ -2,6 +2,7 @@ package http import ( "net/http" + "net/url" "reflect" "testing" @@ -9,7 +10,7 @@ import ( ) func TestSysHealth_get(t *testing.T) { - core, _, _ := vault.TestCoreUnsealed(t) + core, _, root := vault.TestCoreUnsealed(t) ln, addr := TestServer(t, core) defer ln.Close() @@ -30,4 +31,77 @@ func TestSysHealth_get(t *testing.T) { if !reflect.DeepEqual(actual, expected) { t.Fatalf("bad: %#v", actual) } + + core.Seal(root) + + resp, err = http.Get(addr + "/v1/sys/health") + if err != nil { + t.Fatalf("err: %s", err) + } + + actual = map[string]interface{}{} + expected = map[string]interface{}{ + "initialized": true, + "sealed": true, + "standby": false, + } + testResponseStatus(t, resp, 500) + testResponseBody(t, resp, &actual) + expected["server_time_utc"] = actual["server_time_utc"] + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("bad: %#v", actual) + } +} + +func TestSysHealth_customcodes(t *testing.T) { + core, _, root := vault.TestCoreUnsealed(t) + ln, addr := TestServer(t, core) + defer ln.Close() + + queryurl, err := url.Parse(addr + "/v1/sys/health?sealedcode=503&activecode=202") + if err != nil { + t.Fatalf("err: %s", err) + } + resp, err := http.Get(queryurl.String()) + 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, 202) + testResponseBody(t, resp, &actual) + + expected["server_time_utc"] = actual["server_time_utc"] + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("bad: %#v", actual) + } + + core.Seal(root) + + queryurl, err = url.Parse(addr + "/v1/sys/health?sealedcode=503&activecode=202") + if err != nil { + t.Fatalf("err: %s", err) + } + resp, err = http.Get(queryurl.String()) + if err != nil { + t.Fatalf("err: %s", err) + } + + actual = map[string]interface{}{} + expected = map[string]interface{}{ + "initialized": true, + "sealed": true, + "standby": false, + } + testResponseStatus(t, resp, 503) + testResponseBody(t, resp, &actual) + expected["server_time_utc"] = actual["server_time_utc"] + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("bad: %#v", actual) + } } diff --git a/website/source/docs/http/sys-health.html.md b/website/source/docs/http/sys-health.html.md index 19016f9346..9720f12a12 100644 --- a/website/source/docs/http/sys-health.html.md +++ b/website/source/docs/http/sys-health.html.md @@ -11,8 +11,9 @@ description: |-