Change uninit/sealed status codes from health endpoint

This commit is contained in:
Jeff Mitchell
2016-08-18 12:10:23 -04:00
parent 48dbc9d1b5
commit 58a7c8999e
4 changed files with 137 additions and 49 deletions

View File

@@ -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:

View File

@@ -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"]

View File

@@ -44,7 +44,14 @@ description: |-
<span class="param">sealedcode</span>
<span class="param-flags">optional</span>
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`
</li>
<li>
<span class="param">uninitcode</span>
<span class="param-flags">optional</span>
A query parameter provided to indicate the status code that should
be returned for an uninitialized Vault instead of the default of
`501`
</li>
</ul>
</dd>

View File

@@ -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