mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-30 18:17:55 +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 ( | ||||
| 	"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 | ||||
|   | ||||
| @@ -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) | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -11,8 +11,9 @@ description: |- | ||||
| <dl> | ||||
| 	<dt>Description</dt> | ||||
| 	<dd> | ||||
| 		Returns the health status of Vault. This matches the semantics of a Consul HTTP health | ||||
|         check and provides a simple way to monitor the health of a Vault instance. | ||||
|         Returns the health status of Vault. This matches the semantics of a | ||||
|         Consul HTTP health check and provides a simple way to monitor the | ||||
|         health of a Vault instance. | ||||
| 	</dd> | ||||
|  | ||||
| 	<dt>Method</dt> | ||||
| @@ -25,7 +26,25 @@ description: |- | ||||
|             <span class="param">standbyok</span> | ||||
|             <span class="param-flags">optional</span> | ||||
|             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> | ||||
|         </ul> | ||||
| 	</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. | ||||
|  * `500` if not initialized or sealed. | ||||
|  * `500` if sealed, or if not initialized. | ||||
| 	</dd> | ||||
| </dl> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jeff Mitchell
					Jeff Mitchell