|
1 | 1 | package healthsrv |
2 | 2 |
|
3 | 3 | import ( |
4 | | - "encoding/json" |
5 | | - "fmt" |
| 4 | + "log" |
6 | 5 | "net/http" |
7 | 6 | "time" |
8 | 7 |
|
9 | 8 | s3 "github.com/aws/aws-sdk-go/service/s3" |
10 | 9 | "github.com/deis/builder/pkg/sshd" |
11 | | - "github.com/deis/pkg/log" |
12 | 10 | "k8s.io/kubernetes/pkg/api" |
13 | 11 | ) |
14 | 12 |
|
15 | | -type healthZRespBucket struct { |
16 | | - Name string `json:"name"` |
17 | | - CreationDate time.Time `json:"creation_date"` |
18 | | -} |
19 | | - |
20 | | -func convertBucket(b *s3.Bucket) healthZRespBucket { |
21 | | - return healthZRespBucket{ |
22 | | - Name: *b.Name, |
23 | | - CreationDate: *b.CreationDate, |
24 | | - } |
25 | | -} |
26 | | - |
27 | | -type healthZResp struct { |
28 | | - Namespaces []string `json:"k8s_namespaces"` |
29 | | - S3Buckets []healthZRespBucket `json:"s3_buckets"` |
30 | | - SSHServerStarted bool `json:"ssh_server_started"` |
31 | | -} |
32 | | - |
33 | | -func marshalHealthZResp(w http.ResponseWriter, rsp healthZResp) { |
34 | | - if err := json.NewEncoder(w).Encode(rsp); err != nil { |
35 | | - str := fmt.Sprintf("Error encoding JSON (%s)", err) |
36 | | - http.Error(w, str, http.StatusInternalServerError) |
37 | | - return |
38 | | - } |
39 | | -} |
| 13 | +const ( |
| 14 | + waitTimeout = 2 * time.Second |
| 15 | +) |
40 | 16 |
|
41 | 17 | func healthZHandler(nsLister NamespaceLister, bLister BucketLister, serverCircuit *sshd.Circuit) http.Handler { |
42 | 18 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
43 | 19 | stopCh := make(chan struct{}) |
44 | 20 |
|
| 21 | + numChecks := 0 |
45 | 22 | serverStateCh := make(chan struct{}) |
46 | 23 | serverStateErrCh := make(chan error) |
47 | 24 | go circuitState(serverCircuit, serverStateCh, serverStateErrCh, stopCh) |
| 25 | + numChecks++ |
48 | 26 |
|
49 | 27 | listBucketsCh := make(chan *s3.ListBucketsOutput) |
50 | 28 | listBucketsErrCh := make(chan error) |
51 | 29 | go listBuckets(bLister, listBucketsCh, listBucketsErrCh, stopCh) |
| 30 | + numChecks++ |
52 | 31 |
|
53 | 32 | namespaceListerCh := make(chan *api.NamespaceList) |
54 | 33 | namespaceListerErrCh := make(chan error) |
55 | 34 | go listNamespaces(nsLister, namespaceListerCh, namespaceListerErrCh, stopCh) |
| 35 | + numChecks++ |
56 | 36 |
|
57 | | - var rsp healthZResp |
58 | | - serverState, bucketState, namespaceState := false, false, false |
59 | | - for { |
| 37 | + timeoutCh := time.After(waitTimeout) |
| 38 | + defer close(stopCh) |
| 39 | + for i := 0; i < numChecks; i++ { |
60 | 40 | select { |
| 41 | + // ensuring the SSH server has been started |
| 42 | + case <-serverStateCh: |
61 | 43 | case err := <-serverStateErrCh: |
62 | | - log.Err(err.Error()) |
63 | | - http.Error(w, err.Error(), http.StatusServiceUnavailable) |
64 | | - close(stopCh) |
| 44 | + log.Printf("Healthcheck error getting server state (%s)", err) |
| 45 | + w.WriteHeader(http.StatusServiceUnavailable) |
65 | 46 | return |
| 47 | + // listing S3 buckets |
| 48 | + case <-listBucketsCh: |
66 | 49 | case err := <-listBucketsErrCh: |
67 | | - str := fmt.Sprintf("Error listing buckets (%s)", err) |
68 | | - log.Err(str) |
69 | | - http.Error(w, str, http.StatusServiceUnavailable) |
70 | | - close(stopCh) |
| 50 | + log.Printf("Healthcheck error listing buckets (%s)", err) |
| 51 | + w.WriteHeader(http.StatusServiceUnavailable) |
71 | 52 | return |
| 53 | + // listing k8s namespaces |
| 54 | + case <-namespaceListerCh: |
72 | 55 | case err := <-namespaceListerErrCh: |
73 | | - str := fmt.Sprintf("Error listing namespaces (%s)", err) |
74 | | - log.Err(str) |
75 | | - http.Error(w, str, http.StatusServiceUnavailable) |
76 | | - close(stopCh) |
| 56 | + log.Printf("Healthcheck error listing namespaces (%s)", err) |
| 57 | + w.WriteHeader(http.StatusServiceUnavailable) |
| 58 | + return |
| 59 | + // timeout for everything all of the above |
| 60 | + case <-timeoutCh: |
| 61 | + log.Printf("Healthcheck endpoint timed out after %s", waitTimeout) |
| 62 | + w.WriteHeader(http.StatusServiceUnavailable) |
77 | 63 | return |
78 | | - case <-serverStateCh: |
79 | | - serverState = true |
80 | | - rsp.SSHServerStarted = true |
81 | | - if serverState && bucketState && namespaceState { |
82 | | - marshalHealthZResp(w, rsp) |
83 | | - return |
84 | | - } |
85 | | - case lbOut := <-listBucketsCh: |
86 | | - bucketState = true |
87 | | - for _, buck := range lbOut.Buckets { |
88 | | - rsp.S3Buckets = append(rsp.S3Buckets, convertBucket(buck)) |
89 | | - } |
90 | | - if serverState && bucketState && namespaceState { |
91 | | - marshalHealthZResp(w, rsp) |
92 | | - return |
93 | | - } |
94 | | - case nsList := <-namespaceListerCh: |
95 | | - namespaceState = true |
96 | | - for _, ns := range nsList.Items { |
97 | | - rsp.Namespaces = append(rsp.Namespaces, ns.Name) |
98 | | - } |
99 | | - if serverState && bucketState && namespaceState { |
100 | | - marshalHealthZResp(w, rsp) |
101 | | - return |
102 | | - } |
103 | 64 | } |
104 | 65 | } |
| 66 | + w.WriteHeader(http.StatusOK) |
105 | 67 | }) |
106 | 68 | } |
0 commit comments