diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index e2b2894a65..de2f6710d0 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -8973,13 +8973,30 @@ const docTemplate = `{ "GroupSourceOIDC" ] }, + "codersdk.HealthSection": { + "type": "string", + "enum": [ + "DERP", + "AccessURL", + "Websocket", + "Database", + "WorkspaceProxy" + ], + "x-enum-varnames": [ + "HealthSectionDERP", + "HealthSectionAccessURL", + "HealthSectionWebsocket", + "HealthSectionDatabase", + "HealthSectionWorkspaceProxy" + ] + }, "codersdk.HealthSettings": { "type": "object", "properties": { "dismissed_healthchecks": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/codersdk.HealthSection" } } } @@ -10862,7 +10879,7 @@ const docTemplate = `{ "dismissed_healthchecks": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/codersdk.HealthSection" } } } @@ -12550,7 +12567,7 @@ const docTemplate = `{ "description": "FailingSections is a list of sections that have failed their healthcheck.", "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/codersdk.HealthSection" } }, "healthy": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index d62fbfb697..359b8436e4 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -8059,13 +8059,24 @@ "enum": ["user", "oidc"], "x-enum-varnames": ["GroupSourceUser", "GroupSourceOIDC"] }, + "codersdk.HealthSection": { + "type": "string", + "enum": ["DERP", "AccessURL", "Websocket", "Database", "WorkspaceProxy"], + "x-enum-varnames": [ + "HealthSectionDERP", + "HealthSectionAccessURL", + "HealthSectionWebsocket", + "HealthSectionDatabase", + "HealthSectionWorkspaceProxy" + ] + }, "codersdk.HealthSettings": { "type": "object", "properties": { "dismissed_healthchecks": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/codersdk.HealthSection" } } } @@ -9835,7 +9846,7 @@ "dismissed_healthchecks": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/codersdk.HealthSection" } } } @@ -11431,7 +11442,7 @@ "description": "FailingSections is a list of sections that have failed their healthcheck.", "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/codersdk.HealthSection" } }, "healthy": { diff --git a/coderd/coderd.go b/coderd/coderd.go index 08784b6ff4..ee8405bde0 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -413,25 +413,25 @@ func New(options *Options) *API { Database: healthcheck.DatabaseReportOptions{ DB: options.Database, Threshold: options.DeploymentValues.Healthcheck.ThresholdDatabase.Value(), - Dismissed: slices.Contains(dismissedHealthchecks, healthcheck.SectionDatabase), + Dismissed: slices.Contains(dismissedHealthchecks, codersdk.HealthSectionDatabase), }, Websocket: healthcheck.WebsocketReportOptions{ AccessURL: options.AccessURL, APIKey: apiKey, - Dismissed: slices.Contains(dismissedHealthchecks, healthcheck.SectionWebsocket), + Dismissed: slices.Contains(dismissedHealthchecks, codersdk.HealthSectionWebsocket), }, AccessURL: healthcheck.AccessURLReportOptions{ AccessURL: options.AccessURL, - Dismissed: slices.Contains(dismissedHealthchecks, healthcheck.SectionAccessURL), + Dismissed: slices.Contains(dismissedHealthchecks, codersdk.HealthSectionAccessURL), }, DerpHealth: derphealth.ReportOptions{ DERPMap: api.DERPMap(), - Dismissed: slices.Contains(dismissedHealthchecks, healthcheck.SectionDERP), + Dismissed: slices.Contains(dismissedHealthchecks, codersdk.HealthSectionDERP), }, WorkspaceProxy: healthcheck.WorkspaceProxyReportOptions{ CurrentVersion: buildinfo.Version(), WorkspaceProxiesFetchUpdater: *(options.WorkspaceProxiesFetchUpdater).Load(), - Dismissed: slices.Contains(dismissedHealthchecks, healthcheck.SectionWorkspaceProxy), + Dismissed: slices.Contains(dismissedHealthchecks, codersdk.HealthSectionWorkspaceProxy), }, }) } diff --git a/coderd/database/types.go b/coderd/database/types.go index b1fb389d88..d49a06d7c3 100644 --- a/coderd/database/types.go +++ b/coderd/database/types.go @@ -9,6 +9,7 @@ import ( "golang.org/x/xerrors" "github.com/coder/coder/v2/coderd/rbac" + "github.com/coder/coder/v2/codersdk" ) // AuditOAuthConvertState is never stored in the database. It is stored in a cookie @@ -24,8 +25,8 @@ type AuditOAuthConvertState struct { } type HealthSettings struct { - ID uuid.UUID `db:"id" json:"id"` - DismissedHealthchecks []string `db:"dismissed_healthchecks" json:"dismissed_healthchecks"` + ID uuid.UUID `db:"id" json:"id"` + DismissedHealthchecks []codersdk.HealthSection `db:"dismissed_healthchecks" json:"dismissed_healthchecks"` } type Actions []rbac.Action diff --git a/coderd/debug.go b/coderd/debug.go index d447de36ef..16ffb8e179 100644 --- a/coderd/debug.go +++ b/coderd/debug.go @@ -147,7 +147,7 @@ func (api *API) deploymentHealthSettings(rw http.ResponseWriter, r *http.Request } if len(settings.DismissedHealthchecks) == 0 { - settings.DismissedHealthchecks = []string{} + settings.DismissedHealthchecks = []codersdk.HealthSection{} } httpapi.Write(r.Context(), rw, http.StatusOK, settings) @@ -218,6 +218,7 @@ func (api *API) putDeploymentHealthSettings(rw http.ResponseWriter, r *http.Requ Action: database.AuditActionWrite, }) defer commitAudit() + aReq.New = database.HealthSettings{ ID: uuid.New(), DismissedHealthchecks: settings.DismissedHealthchecks, @@ -237,7 +238,7 @@ func (api *API) putDeploymentHealthSettings(rw http.ResponseWriter, r *http.Requ func validateHealthSettings(settings codersdk.HealthSettings) error { for _, dismissed := range settings.DismissedHealthchecks { - ok := slices.Contains(healthcheck.Sections, dismissed) + ok := slices.Contains(codersdk.HealthSections, dismissed) if !ok { return xerrors.Errorf("unknown healthcheck section: %s", dismissed) } @@ -257,8 +258,8 @@ func validateHealthSettings(settings codersdk.HealthSettings) error { // @x-apidocgen {"skip": true} func _debugws(http.ResponseWriter, *http.Request) {} //nolint:unused -func loadDismissedHealthchecks(ctx context.Context, db database.Store, logger slog.Logger) []string { - dismissedHealthchecks := []string{} +func loadDismissedHealthchecks(ctx context.Context, db database.Store, logger slog.Logger) []codersdk.HealthSection { + dismissedHealthchecks := []codersdk.HealthSection{} settingsJSON, err := db.GetHealthSettings(ctx) if err == nil { var settings codersdk.HealthSettings diff --git a/coderd/debug_test.go b/coderd/debug_test.go index 855827c34d..7a020eac67 100644 --- a/coderd/debug_test.go +++ b/coderd/debug_test.go @@ -251,7 +251,7 @@ func TestHealthSettings(t *testing.T) { require.NoError(t, err) // then - require.Equal(t, codersdk.HealthSettings{DismissedHealthchecks: []string{}}, settings) + require.Equal(t, codersdk.HealthSettings{DismissedHealthchecks: []codersdk.HealthSection{}}, settings) }) t.Run("DismissSection", func(t *testing.T) { @@ -265,7 +265,7 @@ func TestHealthSettings(t *testing.T) { _ = coderdtest.CreateFirstUser(t, adminClient) expected := codersdk.HealthSettings{ - DismissedHealthchecks: []string{healthcheck.SectionDERP, healthcheck.SectionWebsocket}, + DismissedHealthchecks: []codersdk.HealthSection{codersdk.HealthSectionDERP, codersdk.HealthSectionWebsocket}, } // when: dismiss "derp" and "websocket" @@ -289,14 +289,14 @@ func TestHealthSettings(t *testing.T) { _ = coderdtest.CreateFirstUser(t, adminClient) initial := codersdk.HealthSettings{ - DismissedHealthchecks: []string{healthcheck.SectionDERP, healthcheck.SectionWebsocket}, + DismissedHealthchecks: []codersdk.HealthSection{codersdk.HealthSectionDERP, codersdk.HealthSectionWebsocket}, } err := adminClient.PutHealthSettings(ctx, initial) require.NoError(t, err) expected := codersdk.HealthSettings{ - DismissedHealthchecks: []string{healthcheck.SectionDERP}, + DismissedHealthchecks: []codersdk.HealthSection{codersdk.HealthSectionDERP}, } // when: undismiss "websocket" @@ -320,7 +320,7 @@ func TestHealthSettings(t *testing.T) { _ = coderdtest.CreateFirstUser(t, adminClient) expected := codersdk.HealthSettings{ - DismissedHealthchecks: []string{healthcheck.SectionDERP, healthcheck.SectionWebsocket}, + DismissedHealthchecks: []codersdk.HealthSection{codersdk.HealthSectionDERP, codersdk.HealthSectionWebsocket}, } err := adminClient.PutHealthSettings(ctx, expected) diff --git a/coderd/healthcheck/healthcheck.go b/coderd/healthcheck/healthcheck.go index 72e96b4ae6..7c63420123 100644 --- a/coderd/healthcheck/healthcheck.go +++ b/coderd/healthcheck/healthcheck.go @@ -9,18 +9,9 @@ import ( "github.com/coder/coder/v2/coderd/healthcheck/derphealth" "github.com/coder/coder/v2/coderd/healthcheck/health" "github.com/coder/coder/v2/coderd/util/ptr" + "github.com/coder/coder/v2/codersdk" ) -const ( - SectionDERP string = "DERP" - SectionAccessURL string = "AccessURL" - SectionWebsocket string = "Websocket" - SectionDatabase string = "Database" - SectionWorkspaceProxy string = "WorkspaceProxy" -) - -var Sections = []string{SectionAccessURL, SectionDatabase, SectionDERP, SectionWebsocket, SectionWorkspaceProxy} - type Checker interface { DERP(ctx context.Context, opts *derphealth.ReportOptions) derphealth.Report AccessURL(ctx context.Context, opts *AccessURLReportOptions) AccessURLReport @@ -39,7 +30,7 @@ type Report struct { // Severity indicates the status of Coder health. Severity health.Severity `json:"severity" enums:"ok,warning,error"` // FailingSections is a list of sections that have failed their healthcheck. - FailingSections []string `json:"failing_sections"` + FailingSections []codersdk.HealthSection `json:"failing_sections"` DERP derphealth.Report `json:"derp"` AccessURL AccessURLReport `json:"access_url"` @@ -162,21 +153,21 @@ func Run(ctx context.Context, opts *ReportOptions) *Report { wg.Wait() report.Time = time.Now() - report.FailingSections = []string{} + report.FailingSections = []codersdk.HealthSection{} if !report.DERP.Healthy { - report.FailingSections = append(report.FailingSections, SectionDERP) + report.FailingSections = append(report.FailingSections, codersdk.HealthSectionDERP) } if !report.AccessURL.Healthy { - report.FailingSections = append(report.FailingSections, SectionAccessURL) + report.FailingSections = append(report.FailingSections, codersdk.HealthSectionAccessURL) } if !report.Websocket.Healthy { - report.FailingSections = append(report.FailingSections, SectionWebsocket) + report.FailingSections = append(report.FailingSections, codersdk.HealthSectionWebsocket) } if !report.Database.Healthy { - report.FailingSections = append(report.FailingSections, SectionDatabase) + report.FailingSections = append(report.FailingSections, codersdk.HealthSectionDatabase) } if !report.WorkspaceProxy.Healthy { - report.FailingSections = append(report.FailingSections, SectionWorkspaceProxy) + report.FailingSections = append(report.FailingSections, codersdk.HealthSectionWorkspaceProxy) } report.Healthy = len(report.FailingSections) == 0 diff --git a/coderd/healthcheck/healthcheck_test.go b/coderd/healthcheck/healthcheck_test.go index 9550cc5cc4..e8089f36eb 100644 --- a/coderd/healthcheck/healthcheck_test.go +++ b/coderd/healthcheck/healthcheck_test.go @@ -9,6 +9,7 @@ import ( "github.com/coder/coder/v2/coderd/healthcheck" "github.com/coder/coder/v2/coderd/healthcheck/derphealth" "github.com/coder/coder/v2/coderd/healthcheck/health" + "github.com/coder/coder/v2/codersdk" ) type testChecker struct { @@ -47,7 +48,7 @@ func TestHealthcheck(t *testing.T) { checker *testChecker healthy bool severity health.Severity - failingSections []string + failingSections []codersdk.HealthSection }{{ name: "OK", checker: &testChecker{ @@ -74,7 +75,7 @@ func TestHealthcheck(t *testing.T) { }, healthy: true, severity: health.SeverityOK, - failingSections: []string{}, + failingSections: []codersdk.HealthSection{}, }, { name: "DERPFail", checker: &testChecker{ @@ -101,7 +102,7 @@ func TestHealthcheck(t *testing.T) { }, healthy: false, severity: health.SeverityError, - failingSections: []string{healthcheck.SectionDERP}, + failingSections: []codersdk.HealthSection{codersdk.HealthSectionDERP}, }, { name: "DERPWarning", checker: &testChecker{ @@ -129,7 +130,7 @@ func TestHealthcheck(t *testing.T) { }, healthy: true, severity: health.SeverityWarning, - failingSections: []string{}, + failingSections: []codersdk.HealthSection{}, }, { name: "AccessURLFail", checker: &testChecker{ @@ -156,7 +157,7 @@ func TestHealthcheck(t *testing.T) { }, healthy: false, severity: health.SeverityWarning, - failingSections: []string{healthcheck.SectionAccessURL}, + failingSections: []codersdk.HealthSection{codersdk.HealthSectionAccessURL}, }, { name: "WebsocketFail", checker: &testChecker{ @@ -183,7 +184,7 @@ func TestHealthcheck(t *testing.T) { }, healthy: false, severity: health.SeverityError, - failingSections: []string{healthcheck.SectionWebsocket}, + failingSections: []codersdk.HealthSection{codersdk.HealthSectionWebsocket}, }, { name: "DatabaseFail", checker: &testChecker{ @@ -210,7 +211,7 @@ func TestHealthcheck(t *testing.T) { }, healthy: false, severity: health.SeverityError, - failingSections: []string{healthcheck.SectionDatabase}, + failingSections: []codersdk.HealthSection{codersdk.HealthSectionDatabase}, }, { name: "ProxyFail", checker: &testChecker{ @@ -237,7 +238,7 @@ func TestHealthcheck(t *testing.T) { }, severity: health.SeverityError, healthy: false, - failingSections: []string{healthcheck.SectionWorkspaceProxy}, + failingSections: []codersdk.HealthSection{codersdk.HealthSectionWorkspaceProxy}, }, { name: "ProxyWarn", checker: &testChecker{ @@ -265,7 +266,7 @@ func TestHealthcheck(t *testing.T) { }, severity: health.SeverityWarning, healthy: true, - failingSections: []string{}, + failingSections: []codersdk.HealthSection{}, }, { name: "AllFail", healthy: false, @@ -292,12 +293,12 @@ func TestHealthcheck(t *testing.T) { }, }, severity: health.SeverityError, - failingSections: []string{ - healthcheck.SectionDERP, - healthcheck.SectionAccessURL, - healthcheck.SectionWebsocket, - healthcheck.SectionDatabase, - healthcheck.SectionWorkspaceProxy, + failingSections: []codersdk.HealthSection{ + codersdk.HealthSectionDERP, + codersdk.HealthSectionAccessURL, + codersdk.HealthSectionWebsocket, + codersdk.HealthSectionDatabase, + codersdk.HealthSectionWorkspaceProxy, }, }} { c := c diff --git a/codersdk/health.go b/codersdk/health.go index 7367df902f..495ce8bb8e 100644 --- a/codersdk/health.go +++ b/codersdk/health.go @@ -8,12 +8,31 @@ import ( "golang.org/x/xerrors" ) +type HealthSection string + +// If you add another const below, make sure to add it to HealthSections! +const ( + HealthSectionDERP HealthSection = "DERP" + HealthSectionAccessURL HealthSection = "AccessURL" + HealthSectionWebsocket HealthSection = "Websocket" + HealthSectionDatabase HealthSection = "Database" + HealthSectionWorkspaceProxy HealthSection = "WorkspaceProxy" +) + +var HealthSections = []HealthSection{ + HealthSectionDERP, + HealthSectionAccessURL, + HealthSectionWebsocket, + HealthSectionDatabase, + HealthSectionWorkspaceProxy, +} + type HealthSettings struct { - DismissedHealthchecks []string `json:"dismissed_healthchecks"` + DismissedHealthchecks []HealthSection `json:"dismissed_healthchecks"` } type UpdateHealthSettings struct { - DismissedHealthchecks []string `json:"dismissed_healthchecks"` + DismissedHealthchecks []HealthSection `json:"dismissed_healthchecks"` } func (c *Client) HealthSettings(ctx context.Context) (HealthSettings, error) { diff --git a/docs/api/debug.md b/docs/api/debug.md index 019ca30ee8..8ea63c39a3 100644 --- a/docs/api/debug.md +++ b/docs/api/debug.md @@ -280,7 +280,7 @@ curl -X GET http://coder-server:8080/api/v2/debug/health \ } ] }, - "failing_sections": ["string"], + "failing_sections": ["DERP"], "healthy": true, "severity": "ok", "time": "string", @@ -362,7 +362,7 @@ curl -X GET http://coder-server:8080/api/v2/debug/health/settings \ ```json { - "dismissed_healthchecks": ["string"] + "dismissed_healthchecks": ["DERP"] } ``` @@ -392,7 +392,7 @@ curl -X PUT http://coder-server:8080/api/v2/debug/health/settings \ ```json { - "dismissed_healthchecks": ["string"] + "dismissed_healthchecks": ["DERP"] } ``` @@ -408,7 +408,7 @@ curl -X PUT http://coder-server:8080/api/v2/debug/health/settings \ ```json { - "dismissed_healthchecks": ["string"] + "dismissed_healthchecks": ["DERP"] } ``` diff --git a/docs/api/schemas.md b/docs/api/schemas.md index 03547650a5..f8a0de0acf 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -3170,19 +3170,37 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | `user` | | `oidc` | +## codersdk.HealthSection + +```json +"DERP" +``` + +### Properties + +#### Enumerated Values + +| Value | +| ---------------- | +| `DERP` | +| `AccessURL` | +| `Websocket` | +| `Database` | +| `WorkspaceProxy` | + ## codersdk.HealthSettings ```json { - "dismissed_healthchecks": ["string"] + "dismissed_healthchecks": ["DERP"] } ``` ### Properties -| Name | Type | Required | Restrictions | Description | -| ------------------------ | --------------- | -------- | ------------ | ----------- | -| `dismissed_healthchecks` | array of string | false | | | +| Name | Type | Required | Restrictions | Description | +| ------------------------ | --------------------------------------------------------- | -------- | ------------ | ----------- | +| `dismissed_healthchecks` | array of [codersdk.HealthSection](#codersdkhealthsection) | false | | | ## codersdk.Healthcheck @@ -5182,15 +5200,15 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in ```json { - "dismissed_healthchecks": ["string"] + "dismissed_healthchecks": ["DERP"] } ``` ### Properties -| Name | Type | Required | Restrictions | Description | -| ------------------------ | --------------- | -------- | ------------ | ----------- | -| `dismissed_healthchecks` | array of string | false | | | +| Name | Type | Required | Restrictions | Description | +| ------------------------ | --------------------------------------------------------- | -------- | ------------ | ----------- | +| `dismissed_healthchecks` | array of [codersdk.HealthSection](#codersdkhealthsection) | false | | | ## codersdk.UpdateRoles @@ -7952,7 +7970,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| } ] }, - "failing_sections": ["string"], + "failing_sections": ["DERP"], "healthy": true, "severity": "ok", "time": "string", @@ -8015,7 +8033,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| | `coder_version` | string | false | | The Coder version of the server that the report was generated on. | | `database` | [healthcheck.DatabaseReport](#healthcheckdatabasereport) | false | | | | `derp` | [derphealth.Report](#derphealthreport) | false | | | -| `failing_sections` | array of string | false | | Failing sections is a list of sections that have failed their healthcheck. | +| `failing_sections` | array of [codersdk.HealthSection](#codersdkhealthsection) | false | | Failing sections is a list of sections that have failed their healthcheck. | | `healthy` | boolean | false | | Healthy is true if the report returns no errors. Deprecated: use `Severity` instead | | `severity` | [health.Severity](#healthseverity) | false | | Severity indicates the status of Coder health. | | `time` | string | false | | Time is the time the report was generated at. | diff --git a/scripts/apitypings/main.go b/scripts/apitypings/main.go index cd02ae81f2..36b2829a8d 100644 --- a/scripts/apitypings/main.go +++ b/scripts/apitypings/main.go @@ -875,6 +875,8 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) { return TypescriptType{ValueType: "HealthMessage"}, nil case "github.com/coder/coder/v2/coderd/healthcheck/health.Severity": return TypescriptType{ValueType: "HealthSeverity"}, nil + case "github.com/coder/coder/v2/codersdk.HealthSection": + return TypescriptType{ValueType: "HealthSection"}, nil } // Some hard codes are a bit trickier. diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 5545336e22..bd058ccb1c 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -544,7 +544,7 @@ export interface Group { // From codersdk/health.go export interface HealthSettings { - readonly dismissed_healthchecks: string[]; + readonly dismissed_healthchecks: HealthSection[]; } // From codersdk/workspaceapps.go @@ -1164,7 +1164,7 @@ export interface UpdateCheckResponse { // From codersdk/health.go export interface UpdateHealthSettings { - readonly dismissed_healthchecks: string[]; + readonly dismissed_healthchecks: HealthSection[]; } // From codersdk/users.go @@ -1795,6 +1795,21 @@ export const FeatureNames: FeatureName[] = [ export type GroupSource = "oidc" | "user"; export const GroupSources: GroupSource[] = ["oidc", "user"]; +// From codersdk/health.go +export type HealthSection = + | "AccessURL" + | "DERP" + | "Database" + | "Websocket" + | "WorkspaceProxy"; +export const HealthSections: HealthSection[] = [ + "AccessURL", + "DERP", + "Database", + "Websocket", + "WorkspaceProxy", +]; + // From codersdk/insights.go export type InsightsReportInterval = "day" | "week"; export const InsightsReportIntervals: InsightsReportInterval[] = [ @@ -2128,7 +2143,7 @@ export interface HealthcheckReport { readonly time: string; readonly healthy: boolean; readonly severity: HealthSeverity; - readonly failing_sections: string[]; + readonly failing_sections: HealthSection[]; readonly derp: DerphealthReport; readonly access_url: HealthcheckAccessURLReport; readonly websocket: HealthcheckWebsocketReport;