mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 02:28:09 +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
	 Jeff Mitchell
					Jeff Mitchell