-
Notifications
You must be signed in to change notification settings - Fork 2
/
main.go
143 lines (117 loc) · 3.29 KB
/
main.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
132
133
134
135
136
137
138
139
140
141
142
143
package main
import (
"encoding/json"
"flag"
"fmt"
"log"
"net/http"
"os"
"strings"
)
// Hostnames contain the list of hosts that are being checked agains.
var Hostnames = strings.Split(os.Getenv("HEALTH_CHECK_HOSTNAMES"), ",")
// The port the host is listening on, usually 80
var HostPort = os.Getenv("HEALTH_CHECK_HOST_PORT")
// HTTPResponse contains the http response data to the specified host
type HTTPResponse struct {
hostname string
response *http.Response
err error
check string
}
// CheckResponse contains the HTTP status response from the specified host
type CheckResponse struct {
Status int `json:"status"`
Check string `json:"check"`
}
func main() {
port := ""
flag.StringVar(&port, "port", "9292", "the port to listen on")
flag.Parse()
fmt.Fprintln(os.Stderr, "starting listener on port", port)
http.HandleFunc("/", mainHandler)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
}
func mainHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
allowedToFailQueryParam := r.URL.Query().Get("allowed_to_fail")
mustSucceedQueryParam := r.URL.Query().Get("must_succeed")
hostnamesAllowedToFail := strings.Split(allowedToFailQueryParam, ",")
hostnamesMustSucceed := strings.Split(mustSucceedQueryParam, ",")
ch := make(chan *HTTPResponse, len(Hostnames))
for _, hostname := range Hostnames {
go makeRequest(hostname, ch)
}
// Block until we get responses for all hostnames
responses := []*HTTPResponse{}
for range Hostnames {
responses = append(responses, <-ch)
}
httpResponseData := make(map[string]CheckResponse)
for _, r := range responses {
var code int
if r.response != nil {
code = r.response.StatusCode
}
httpResponseData[r.hostname] = CheckResponse{code, r.check}
}
filteredResponses := []*HTTPResponse{}
if len(hostnamesAllowedToFail) > 0 {
for _, r := range responses {
if !contains(hostnamesAllowedToFail, r.hostname) {
filteredResponses = append(filteredResponses, r)
}
}
} else if len(hostnamesMustSucceed) > 0 {
for _, r := range responses {
if contains(hostnamesMustSucceed, r.hostname) {
filteredResponses = append(filteredResponses, r)
}
}
} else {
for _, r := range responses {
filteredResponses = append(filteredResponses, r)
}
}
failedAnywhere := false
for _, fr := range filteredResponses {
if fr.check == "failure" {
failedAnywhere = true
}
}
if failedAnywhere {
w.WriteHeader(http.StatusInternalServerError)
}
json, err := json.Marshal(httpResponseData)
if err != nil {
fmt.Println(err)
}
fmt.Fprintf(w, string(json))
}
func makeRequest(hostname string, ch chan<- *HTTPResponse) {
client := &http.Client{}
if HostPort == "" {
HostPort = "80"
}
check_url := fmt.Sprintf("http://0.0.0.0:%s/health_check", HostPort)
req, _ := http.NewRequest("HEAD", check_url, nil)
req.Host = hostname
req.Header.Add("X-Forwarded-Proto", "https")
resp, err := client.Do(req)
check := "failure"
if resp != nil {
resp.Body.Close()
if resp.StatusCode >= 200 && resp.StatusCode <= 209 {
check = "success"
}
}
ch <- &HTTPResponse{hostname, resp, err, check}
}
func contains(stringSlice []string, searchString string) bool {
for _, value := range stringSlice {
if value == searchString {
return true
}
}
return false
}