Skip to content

Commit a01878e

Browse files
committed
API
1 parent c684b48 commit a01878e

File tree

2 files changed

+101
-21
lines changed

2 files changed

+101
-21
lines changed

coderd/debug.go

Lines changed: 99 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@ package coderd
22

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

910
"github.com/coder/coder/v2/coderd/healthcheck"
1011
"github.com/coder/coder/v2/coderd/httpapi"
1112
"github.com/coder/coder/v2/coderd/httpmw"
13+
"github.com/coder/coder/v2/coderd/rbac"
1214
"github.com/coder/coder/v2/codersdk"
15+
"golang.org/x/exp/slices"
16+
"golang.org/x/xerrors"
1317
)
1418

1519
// @Summary Debug Info Wireguard Coordinator
@@ -82,6 +86,31 @@ func (api *API) debugDeploymentHealth(rw http.ResponseWriter, r *http.Request) {
8286
}
8387
}
8488

89+
func formatHealthcheck(ctx context.Context, rw http.ResponseWriter, r *http.Request, hc *healthcheck.Report) {
90+
format := r.URL.Query().Get("format")
91+
switch format {
92+
case "text":
93+
rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
94+
rw.WriteHeader(http.StatusOK)
95+
96+
_, _ = fmt.Fprintln(rw, "time:", hc.Time.Format(time.RFC3339))
97+
_, _ = fmt.Fprintln(rw, "healthy:", hc.Healthy)
98+
_, _ = fmt.Fprintln(rw, "derp:", hc.DERP.Healthy)
99+
_, _ = fmt.Fprintln(rw, "access_url:", hc.AccessURL.Healthy)
100+
_, _ = fmt.Fprintln(rw, "websocket:", hc.Websocket.Healthy)
101+
_, _ = fmt.Fprintln(rw, "database:", hc.Database.Healthy)
102+
103+
case "", "json":
104+
httpapi.WriteIndent(ctx, rw, http.StatusOK, hc)
105+
106+
default:
107+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
108+
Message: fmt.Sprintf("Invalid format option %q.", format),
109+
Detail: "Allowed values are: \"json\", \"simple\".",
110+
})
111+
}
112+
}
113+
85114
// @Summary Get health settings
86115
// @ID get-health-settings
87116
// @Security CoderSessionToken
@@ -90,7 +119,30 @@ func (api *API) debugDeploymentHealth(rw http.ResponseWriter, r *http.Request) {
90119
// @Success 200 {object} codersdk.HealthSettings
91120
// @Router /debug/health/settings [get]
92121
func (api *API) deploymentHealthSettings(rw http.ResponseWriter, r *http.Request) {
93-
// TODO
122+
settingsJSON, err := api.Database.GetHealthSettings(r.Context())
123+
if err != nil {
124+
httpapi.Write(r.Context(), rw, http.StatusInternalServerError, codersdk.Response{
125+
Message: "Failed to fetch health settings.",
126+
Detail: err.Error(),
127+
})
128+
return
129+
}
130+
131+
var settings codersdk.HealthSettings
132+
err = json.Unmarshal([]byte(settingsJSON), &settings)
133+
if err != nil {
134+
httpapi.Write(r.Context(), rw, http.StatusInternalServerError, codersdk.Response{
135+
Message: "Failed to unmarshal health settings.",
136+
Detail: err.Error(),
137+
})
138+
return
139+
}
140+
141+
if len(settings.DismissedHealthchecks) == 0 {
142+
settings.DismissedHealthchecks = []string{}
143+
}
144+
145+
httpapi.Write(r.Context(), rw, http.StatusOK, settings)
94146
}
95147

96148
// @Summary Update health settings
@@ -103,32 +155,58 @@ func (api *API) deploymentHealthSettings(rw http.ResponseWriter, r *http.Request
103155
// @Success 200 {object} codersdk.UpdateHealthSettings
104156
// @Router /debug/health/settings [put]
105157
func (api *API) putDeploymentHealthSettings(rw http.ResponseWriter, r *http.Request) {
106-
// TODO
107-
}
158+
ctx := r.Context()
108159

109-
func formatHealthcheck(ctx context.Context, rw http.ResponseWriter, r *http.Request, hc *healthcheck.Report) {
110-
format := r.URL.Query().Get("format")
111-
switch format {
112-
case "text":
113-
rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
114-
rw.WriteHeader(http.StatusOK)
160+
if !api.Authorize(r, rbac.ActionUpdate, rbac.ResourceDeploymentValues) {
161+
httpapi.Write(ctx, rw, http.StatusForbidden, codersdk.Response{
162+
Message: "Insufficient permissions to update health settings.",
163+
})
164+
return
165+
}
115166

116-
_, _ = fmt.Fprintln(rw, "time:", hc.Time.Format(time.RFC3339))
117-
_, _ = fmt.Fprintln(rw, "healthy:", hc.Healthy)
118-
_, _ = fmt.Fprintln(rw, "derp:", hc.DERP.Healthy)
119-
_, _ = fmt.Fprintln(rw, "access_url:", hc.AccessURL.Healthy)
120-
_, _ = fmt.Fprintln(rw, "websocket:", hc.Websocket.Healthy)
121-
_, _ = fmt.Fprintln(rw, "database:", hc.Database.Healthy)
167+
var settings codersdk.HealthSettings
168+
if !httpapi.Read(ctx, rw, r, &settings) {
169+
return
170+
}
122171

123-
case "", "json":
124-
httpapi.WriteIndent(ctx, rw, http.StatusOK, hc)
172+
err := validateHealthSettings(settings)
173+
if err != nil {
174+
httpapi.Write(r.Context(), rw, http.StatusInternalServerError, codersdk.Response{
175+
Message: "Failed to validate health settings.",
176+
Detail: err.Error(),
177+
})
178+
return
179+
}
125180

126-
default:
127-
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
128-
Message: fmt.Sprintf("Invalid format option %q.", format),
129-
Detail: "Allowed values are: \"json\", \"simple\".",
181+
settingsJSON, err := json.Marshal(&settings)
182+
if err != nil {
183+
httpapi.Write(r.Context(), rw, http.StatusInternalServerError, codersdk.Response{
184+
Message: "Failed to marshal health settings.",
185+
Detail: err.Error(),
186+
})
187+
return
188+
}
189+
190+
err = api.Database.UpsertHealthSettings(ctx, string(settingsJSON))
191+
if err != nil {
192+
httpapi.Write(r.Context(), rw, http.StatusInternalServerError, codersdk.Response{
193+
Message: "Failed to update health settings.",
194+
Detail: err.Error(),
130195
})
196+
return
197+
}
198+
199+
httpapi.Write(r.Context(), rw, http.StatusOK, settings)
200+
}
201+
202+
func validateHealthSettings(settings codersdk.HealthSettings) error {
203+
for _, dismissed := range settings.DismissedHealthchecks {
204+
ok := slices.Contains(healthcheck.Sections, dismissed)
205+
if !ok {
206+
return xerrors.Errorf("unknown healthcheck section: %s", dismissed)
207+
}
131208
}
209+
return nil
132210
}
133211

134212
// For some reason the swagger docs need to be attached to a function.

coderd/healthcheck/healthcheck.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ const (
2020
SectionWorkspaceProxy string = "WorkspaceProxy"
2121
)
2222

23+
var Sections = []string{SectionAccessURL, SectionDatabase, SectionDERP, SectionWebsocket, SectionWorkspaceProxy}
24+
2325
type Checker interface {
2426
DERP(ctx context.Context, opts *derphealth.ReportOptions) derphealth.Report
2527
AccessURL(ctx context.Context, opts *AccessURLReportOptions) AccessURLReport

0 commit comments

Comments
 (0)