diff --git a/http/sys_health.go b/http/sys_health.go index da5922c5be..771c5d6b79 100644 --- a/http/sys_health.go +++ b/http/sys_health.go @@ -73,9 +73,14 @@ func getSysHealth(core *vault.Core, r *http.Request) (int, *HealthResponse, erro // 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 + uninitCode := http.StatusNotImplemented + if code, found, ok := fetchStatusCode(r, "uninitcode"); !ok { + return http.StatusBadRequest, nil, nil + } else if found { + uninitCode = code + } + + sealedCode := http.StatusServiceUnavailable if code, found, ok := fetchStatusCode(r, "sealedcode"); !ok { return http.StatusBadRequest, nil, nil } else if found { @@ -108,7 +113,7 @@ func getSysHealth(core *vault.Core, r *http.Request) (int, *HealthResponse, erro code := activeCode switch { case !init: - code = http.StatusInternalServerError + code = uninitCode case sealed: code = sealedCode case !standbyOK && standby: diff --git a/http/sys_health_test.go b/http/sys_health_test.go index 0709620521..5eab21e979 100644 --- a/http/sys_health_test.go +++ b/http/sys_health_test.go @@ -12,7 +12,7 @@ import ( ) func TestSysHealth_get(t *testing.T) { - core, _, root := vault.TestCoreUnsealed(t) + core := vault.TestCore(t) ln, addr := TestServer(t, core) defer ln.Close() @@ -23,6 +23,68 @@ func TestSysHealth_get(t *testing.T) { var actual map[string]interface{} expected := map[string]interface{}{ + "initialized": false, + "sealed": true, + "standby": true, + } + testResponseStatus(t, resp, 501) + testResponseBody(t, resp, &actual) + expected["server_time_utc"] = actual["server_time_utc"] + expected["version"] = actual["version"] + if actual["cluster_name"] == nil { + delete(expected, "cluster_name") + } else { + expected["cluster_name"] = actual["cluster_name"] + } + if actual["cluster_id"] == nil { + delete(expected, "cluster_id") + } else { + expected["cluster_id"] = actual["cluster_id"] + } + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual) + } + + key, _ := vault.TestCoreInit(t, core) + 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": true, + } + testResponseStatus(t, resp, 503) + testResponseBody(t, resp, &actual) + expected["server_time_utc"] = actual["server_time_utc"] + expected["version"] = actual["version"] + if actual["cluster_name"] == nil { + delete(expected, "cluster_name") + } else { + expected["cluster_name"] = actual["cluster_name"] + } + if actual["cluster_id"] == nil { + delete(expected, "cluster_id") + } else { + expected["cluster_id"] = actual["cluster_id"] + } + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual) + } + + if _, err := vault.TestCoreUnseal(core, vault.TestKeyCopy(key)); err != nil { + t.Fatalf("unseal err: %s", err) + } + 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": false, "standby": false, @@ -45,44 +107,14 @@ func TestSysHealth_get(t *testing.T) { t.Fatalf("bad: expected:%#v\nactual:%#v", expected, 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"] - expected["version"] = actual["version"] - if actual["cluster_name"] == nil { - delete(expected, "cluster_name") - } else { - expected["cluster_name"] = actual["cluster_name"] - } - if actual["cluster_id"] == nil { - delete(expected, "cluster_id") - } else { - expected["cluster_id"] = actual["cluster_id"] - } - if !reflect.DeepEqual(actual, expected) { - t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual) - } } func TestSysHealth_customcodes(t *testing.T) { - core, _, root := vault.TestCoreUnsealed(t) + core := vault.TestCore(t) ln, addr := TestServer(t, core) defer ln.Close() - queryurl, err := url.Parse(addr + "/v1/sys/health?sealedcode=503&activecode=202") + queryurl, err := url.Parse(addr + "/v1/sys/health?uninitcode=581&sealedcode=523&activecode=202") if err != nil { t.Fatalf("err: %s", err) } @@ -93,11 +125,11 @@ func TestSysHealth_customcodes(t *testing.T) { var actual map[string]interface{} expected := map[string]interface{}{ - "initialized": true, - "sealed": false, - "standby": false, + "initialized": false, + "sealed": true, + "standby": true, } - testResponseStatus(t, resp, 202) + testResponseStatus(t, resp, 581) testResponseBody(t, resp, &actual) expected["server_time_utc"] = actual["server_time_utc"] @@ -116,12 +148,7 @@ func TestSysHealth_customcodes(t *testing.T) { t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual) } - core.Seal(root) - - queryurl, err = url.Parse(addr + "/v1/sys/health?sealedcode=503&activecode=202") - if err != nil { - t.Fatalf("err: %s", err) - } + key, _ := vault.TestCoreInit(t, core) resp, err = http.Get(queryurl.String()) if err != nil { t.Fatalf("err: %s", err) @@ -131,9 +158,42 @@ func TestSysHealth_customcodes(t *testing.T) { expected = map[string]interface{}{ "initialized": true, "sealed": true, + "standby": true, + } + testResponseStatus(t, resp, 523) + testResponseBody(t, resp, &actual) + + expected["server_time_utc"] = actual["server_time_utc"] + expected["version"] = actual["version"] + if actual["cluster_name"] == nil { + delete(expected, "cluster_name") + } else { + expected["cluster_name"] = actual["cluster_name"] + } + if actual["cluster_id"] == nil { + delete(expected, "cluster_id") + } else { + expected["cluster_id"] = actual["cluster_id"] + } + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual) + } + + if _, err := vault.TestCoreUnseal(core, vault.TestKeyCopy(key)); err != nil { + t.Fatalf("unseal 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": false, "standby": false, } - testResponseStatus(t, resp, 503) + testResponseStatus(t, resp, 202) testResponseBody(t, resp, &actual) expected["server_time_utc"] = actual["server_time_utc"] expected["version"] = actual["version"] diff --git a/website/source/docs/http/sys-health.html.md b/website/source/docs/http/sys-health.html.md index cd770c59e7..5476325382 100644 --- a/website/source/docs/http/sys-health.html.md +++ b/website/source/docs/http/sys-health.html.md @@ -44,7 +44,14 @@ description: |- sealedcode optional A query parameter provided to indicate the status code that should - be returned for a sealed node instead of the default of `500` + be returned for a sealed node instead of the default of `503` + +
  • + uninitcode + optional + A query parameter provided to indicate the status code that should + be returned for an uninitialized Vault instead of the default of + `501`
  • diff --git a/website/source/docs/install/upgrade-to-0.6.1.html.md b/website/source/docs/install/upgrade-to-0.6.1.html.md index e8bca41a99..e5fd7e73ff 100644 --- a/website/source/docs/install/upgrade-to-0.6.1.html.md +++ b/website/source/docs/install/upgrade-to-0.6.1.html.md @@ -18,6 +18,22 @@ able to form an HA cluster. If following our [general upgrade instructions](https://www.vaultproject.io/docs/install/upgrade.html) this will not be an issue. +## Health Endpoint Status Code Changes + +Prior to 0.6.1, the health endpoint would return a `500` (Internal Server +Error) for both a sealed and uninitialized state. In both states this was +confusing, since it was hard to tell, based on the status code, an actual +internal error from Vault from a Vault that was simply uninitialized or sealed, +not to mention differentiating between those two states. + +In 0.6.1, a sealed Vault will return a `503` (Service Unavailable) status code. +As before, this can be adjusted with the `sealedcode` query parameter. An +uninitialized Vault will return a `501` (Not Implemented) status code. This can +be adjusted with the `uninitcode` query parameter. + +This removes ambiguity/confusion and falls more in line with the intention of +each status code (including `500`). + ## Root Token Creation Restrictions Root tokens (tokens with the `root` policy) can no longer be created except by