forked from hashicorp/vault
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sys_health.go
131 lines (113 loc) · 3.1 KB
/
sys_health.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package http
import (
"encoding/json"
"net/http"
"strconv"
"time"
"github.com/hashicorp/vault/vault"
)
func handleSysHealth(core *vault.Core) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "GET":
handleSysHealthGet(core, w, r)
case "HEAD":
handleSysHealthHead(core, w, r)
default:
respondError(w, http.StatusMethodNotAllowed, nil)
}
})
}
func fetchStatusCode(r *http.Request, field string) (int, bool, bool) {
var err error
statusCode := http.StatusOK
if statusCodeStr, statusCodeOk := r.URL.Query()[field]; statusCodeOk {
statusCode, err = strconv.Atoi(statusCodeStr[0])
if err != nil || len(statusCodeStr) < 1 {
return http.StatusBadRequest, false, false
}
return statusCode, true, true
}
return statusCode, false, true
}
func handleSysHealthGet(core *vault.Core, w http.ResponseWriter, r *http.Request) {
code, body, err := getSysHealth(core, r)
if err != nil {
respondError(w, http.StatusInternalServerError, nil)
return
}
if body == nil {
respondError(w, code, nil)
return
}
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(code)
// Generate the response
enc := json.NewEncoder(w)
enc.Encode(body)
}
func handleSysHealthHead(core *vault.Core, w http.ResponseWriter, r *http.Request) {
code, body, err := getSysHealth(core, r)
if err != nil {
code = http.StatusInternalServerError
}
if body != nil {
w.Header().Add("Content-Type", "application/json")
}
w.WriteHeader(code)
}
func getSysHealth(core *vault.Core, r *http.Request) (int, *HealthResponse, error) {
// 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
if code, found, ok := fetchStatusCode(r, "sealedcode"); !ok {
return http.StatusBadRequest, nil, nil
} else if found {
sealedCode = code
}
standbyCode := http.StatusTooManyRequests // Consul warning code
if code, found, ok := fetchStatusCode(r, "standbycode"); !ok {
return http.StatusBadRequest, nil, nil
} else if found {
standbyCode = code
}
activeCode := http.StatusOK
if code, found, ok := fetchStatusCode(r, "activecode"); !ok {
return http.StatusBadRequest, nil, nil
} else if found {
activeCode = code
}
// Check system status
sealed, _ := core.Sealed()
standby, _ := core.Standby()
init, err := core.Initialized()
if err != nil {
return http.StatusInternalServerError, nil, err
}
// Determine the status code
code := activeCode
switch {
case !init:
code = http.StatusInternalServerError
case sealed:
code = sealedCode
case !standbyOK && standby:
code = standbyCode
}
// Format the body
body := &HealthResponse{
Initialized: init,
Sealed: sealed,
Standby: standby,
ServerTimeUTC: time.Now().UTC().Unix(),
}
return code, body, nil
}
type HealthResponse struct {
Initialized bool `json:"initialized"`
Sealed bool `json:"sealed"`
Standby bool `json:"standby"`
ServerTimeUTC int64 `json:"server_time_utc"`
}