@@ -2,14 +2,18 @@ package coderd
2
2
3
3
import (
4
4
"context"
5
+ "encoding/json"
5
6
"fmt"
6
7
"net/http"
7
8
"time"
8
9
9
10
"github.com/coder/coder/v2/coderd/healthcheck"
10
11
"github.com/coder/coder/v2/coderd/httpapi"
11
12
"github.com/coder/coder/v2/coderd/httpmw"
13
+ "github.com/coder/coder/v2/coderd/rbac"
12
14
"github.com/coder/coder/v2/codersdk"
15
+ "golang.org/x/exp/slices"
16
+ "golang.org/x/xerrors"
13
17
)
14
18
15
19
// @Summary Debug Info Wireguard Coordinator
@@ -82,6 +86,31 @@ func (api *API) debugDeploymentHealth(rw http.ResponseWriter, r *http.Request) {
82
86
}
83
87
}
84
88
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
+
85
114
// @Summary Get health settings
86
115
// @ID get-health-settings
87
116
// @Security CoderSessionToken
@@ -90,7 +119,30 @@ func (api *API) debugDeploymentHealth(rw http.ResponseWriter, r *http.Request) {
90
119
// @Success 200 {object} codersdk.HealthSettings
91
120
// @Router /debug/health/settings [get]
92
121
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 )
94
146
}
95
147
96
148
// @Summary Update health settings
@@ -103,32 +155,58 @@ func (api *API) deploymentHealthSettings(rw http.ResponseWriter, r *http.Request
103
155
// @Success 200 {object} codersdk.UpdateHealthSettings
104
156
// @Router /debug/health/settings [put]
105
157
func (api * API ) putDeploymentHealthSettings (rw http.ResponseWriter , r * http.Request ) {
106
- // TODO
107
- }
158
+ ctx := r .Context ()
108
159
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
+ }
115
166
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
+ }
122
171
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
+ }
125
180
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 (),
130
195
})
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
+ }
131
208
}
209
+ return nil
132
210
}
133
211
134
212
// For some reason the swagger docs need to be attached to a function.
0 commit comments