Skip to content

Commit 8929226

Browse files
authored
feat(coderd): add simple healthcheck formatting option (#9864)
1 parent 6e6b808 commit 8929226

File tree

2 files changed

+65
-3
lines changed

2 files changed

+65
-3
lines changed

coderd/debug.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package coderd
22

33
import (
44
"context"
5+
"fmt"
56
"net/http"
67
"time"
78

@@ -37,7 +38,7 @@ func (api *API) debugDeploymentHealth(rw http.ResponseWriter, r *http.Request) {
3738
// Get cached report if it exists.
3839
if report := api.healthCheckCache.Load(); report != nil {
3940
if time.Since(report.Time) < api.HealthcheckRefresh {
40-
httpapi.WriteIndent(ctx, rw, http.StatusOK, report)
41+
formatHealthcheck(ctx, rw, r, report)
4142
return
4243
}
4344
}
@@ -59,11 +60,36 @@ func (api *API) debugDeploymentHealth(rw http.ResponseWriter, r *http.Request) {
5960
})
6061
return
6162
case res := <-resChan:
62-
httpapi.WriteIndent(ctx, rw, http.StatusOK, res.Val)
63+
formatHealthcheck(ctx, rw, r, res.Val)
6364
return
6465
}
6566
}
6667

68+
func formatHealthcheck(ctx context.Context, rw http.ResponseWriter, r *http.Request, hc *healthcheck.Report) {
69+
format := r.URL.Query().Get("format")
70+
switch format {
71+
case "text":
72+
rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
73+
rw.WriteHeader(http.StatusOK)
74+
75+
_, _ = fmt.Fprintln(rw, "time:", hc.Time.Format(time.RFC3339))
76+
_, _ = fmt.Fprintln(rw, "healthy:", hc.Healthy)
77+
_, _ = fmt.Fprintln(rw, "derp:", hc.DERP.Healthy)
78+
_, _ = fmt.Fprintln(rw, "access_url:", hc.AccessURL.Healthy)
79+
_, _ = fmt.Fprintln(rw, "websocket:", hc.Websocket.Healthy)
80+
_, _ = fmt.Fprintln(rw, "database:", hc.Database.Healthy)
81+
82+
case "", "json":
83+
httpapi.WriteIndent(ctx, rw, http.StatusOK, hc)
84+
85+
default:
86+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
87+
Message: fmt.Sprintf("Invalid format option %q.", format),
88+
Detail: "Allowed values are: \"json\", \"simple\".",
89+
})
90+
}
91+
}
92+
6793
// For some reason the swagger docs need to be attached to a function.
6894
//
6995
// @Summary Debug Info Websocket Test

coderd/debug_test.go

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
"github.com/coder/coder/v2/coderd/coderdtest"
1414
"github.com/coder/coder/v2/coderd/healthcheck"
15+
"github.com/coder/coder/v2/coderd/healthcheck/derphealth"
1516
"github.com/coder/coder/v2/testutil"
1617
)
1718

@@ -34,7 +35,7 @@ func TestDebugHealth(t *testing.T) {
3435
defer cancel()
3536

3637
sessionToken = client.SessionToken()
37-
res, err := client.Request(ctx, "GET", "/debug/health", nil)
38+
res, err := client.Request(ctx, "GET", "/api/v2/debug/health", nil)
3839
require.NoError(t, err)
3940
defer res.Body.Close()
4041
_, _ = io.ReadAll(res.Body)
@@ -106,6 +107,41 @@ func TestDebugHealth(t *testing.T) {
106107
require.Equal(t, http.StatusOK, res.StatusCode)
107108
require.Equal(t, 1, calls)
108109
})
110+
111+
t.Run("Text", func(t *testing.T) {
112+
t.Parallel()
113+
114+
var (
115+
ctx, cancel = context.WithTimeout(context.Background(), testutil.WaitShort)
116+
sessionToken string
117+
client = coderdtest.New(t, &coderdtest.Options{
118+
HealthcheckFunc: func(_ context.Context, apiKey string) *healthcheck.Report {
119+
assert.Equal(t, sessionToken, apiKey)
120+
return &healthcheck.Report{
121+
Time: time.Now(),
122+
Healthy: true,
123+
DERP: derphealth.Report{Healthy: true},
124+
}
125+
},
126+
})
127+
_ = coderdtest.CreateFirstUser(t, client)
128+
)
129+
defer cancel()
130+
131+
sessionToken = client.SessionToken()
132+
res, err := client.Request(ctx, "GET", "/api/v2/debug/health?format=text", nil)
133+
require.NoError(t, err)
134+
defer res.Body.Close()
135+
resB, _ := io.ReadAll(res.Body)
136+
require.Equal(t, http.StatusOK, res.StatusCode)
137+
138+
resStr := string(resB)
139+
assert.Contains(t, resStr, "healthy: true")
140+
assert.Contains(t, resStr, "derp: true")
141+
assert.Contains(t, resStr, "access_url: false")
142+
assert.Contains(t, resStr, "websocket: false")
143+
assert.Contains(t, resStr, "database: false")
144+
})
109145
}
110146

111147
func TestDebugWebsocket(t *testing.T) {

0 commit comments

Comments
 (0)