mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-31 18:48:08 +00:00
Add query parameters to /sys/health to specify return codes.
Fixes #1199
This commit is contained in:
@@ -3,6 +3,7 @@ package http
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/vault/vault"
|
"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) {
|
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
|
// Check if being a standby is allowed for the purpose of a 200 OK
|
||||||
_, standbyOK := r.URL.Query()["standbyok"]
|
_, 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
|
// Check system status
|
||||||
sealed, _ := core.Sealed()
|
sealed, _ := core.Sealed()
|
||||||
standby, _ := core.Standby()
|
standby, _ := core.Standby()
|
||||||
@@ -33,14 +81,14 @@ func handleSysHealthGet(core *vault.Core, w http.ResponseWriter, r *http.Request
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine the status code
|
// Determine the status code
|
||||||
code := http.StatusOK
|
code := activeCode
|
||||||
switch {
|
switch {
|
||||||
case !init:
|
case !init:
|
||||||
code = http.StatusInternalServerError
|
code = http.StatusInternalServerError
|
||||||
case sealed:
|
case sealed:
|
||||||
code = http.StatusInternalServerError
|
code = sealedCode
|
||||||
case !standbyOK && standby:
|
case !standbyOK && standby:
|
||||||
code = 429 // Consul warning code
|
code = standbyCode
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format the body
|
// Format the body
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package http
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -9,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestSysHealth_get(t *testing.T) {
|
func TestSysHealth_get(t *testing.T) {
|
||||||
core, _, _ := vault.TestCoreUnsealed(t)
|
core, _, root := vault.TestCoreUnsealed(t)
|
||||||
ln, addr := TestServer(t, core)
|
ln, addr := TestServer(t, core)
|
||||||
defer ln.Close()
|
defer ln.Close()
|
||||||
|
|
||||||
@@ -30,4 +31,77 @@ func TestSysHealth_get(t *testing.T) {
|
|||||||
if !reflect.DeepEqual(actual, expected) {
|
if !reflect.DeepEqual(actual, expected) {
|
||||||
t.Fatalf("bad: %#v", actual)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,9 @@ description: |-
|
|||||||
<dl>
|
<dl>
|
||||||
<dt>Description</dt>
|
<dt>Description</dt>
|
||||||
<dd>
|
<dd>
|
||||||
Returns the health status of Vault. This matches the semantics of a Consul HTTP health
|
Returns the health status of Vault. This matches the semantics of a
|
||||||
check and provides a simple way to monitor the health of a Vault instance.
|
Consul HTTP health check and provides a simple way to monitor the
|
||||||
|
health of a Vault instance.
|
||||||
</dd>
|
</dd>
|
||||||
|
|
||||||
<dt>Method</dt>
|
<dt>Method</dt>
|
||||||
@@ -25,7 +26,25 @@ description: |-
|
|||||||
<span class="param">standbyok</span>
|
<span class="param">standbyok</span>
|
||||||
<span class="param-flags">optional</span>
|
<span class="param-flags">optional</span>
|
||||||
A query parameter provided to indicate that being a standby should
|
A query parameter provided to indicate that being a standby should
|
||||||
still return a 200 status code instead of the standard 429 status code.
|
still return the active status code instead of the standby code
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span class="param">activecode</span>
|
||||||
|
<span class="param-flags">optional</span>
|
||||||
|
A query parameter provided to indicate the status code that should
|
||||||
|
be returned for an active node instead of the default of `200`
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span class="param">standbycode</span>
|
||||||
|
<span class="param-flags">optional</span>
|
||||||
|
A query parameter provided to indicate the status code that should
|
||||||
|
be returned for a standby node instead of the default of `429`
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<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`
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</dd>
|
</dd>
|
||||||
@@ -41,10 +60,10 @@ description: |-
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Status Codes:
|
Default Status Codes:
|
||||||
|
|
||||||
* `200` if initialized, unsealed and active.
|
* `200` if initialized, unsealed, and active.
|
||||||
* `429` if unsealed and standby.
|
* `429` if unsealed and standby.
|
||||||
* `500` if not initialized or sealed.
|
* `500` if sealed, or if not initialized.
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|||||||
Reference in New Issue
Block a user