fix(site): add workspace proxy section to health page (#10862)

* Adds workspace proxy section to health page
* Conditionally places workspace proxy warnings in errors or warnings based on calculated severity
* Adds some more stories we were missing for HealthPage
This commit is contained in:
Cian Johnston
2023-11-27 09:26:02 +00:00
committed by GitHub
parent 6c67add2d9
commit b73397e08c
5 changed files with 170 additions and 14 deletions

View File

@ -238,6 +238,34 @@ func TestHealthcheck(t *testing.T) {
severity: health.SeverityError, severity: health.SeverityError,
healthy: false, healthy: false,
failingSections: []string{healthcheck.SectionWorkspaceProxy}, failingSections: []string{healthcheck.SectionWorkspaceProxy},
}, {
name: "ProxyWarn",
checker: &testChecker{
DERPReport: derphealth.Report{
Healthy: true,
Severity: health.SeverityOK,
},
AccessURLReport: healthcheck.AccessURLReport{
Healthy: true,
Severity: health.SeverityOK,
},
WebsocketReport: healthcheck.WebsocketReport{
Healthy: true,
Severity: health.SeverityOK,
},
DatabaseReport: healthcheck.DatabaseReport{
Healthy: true,
Severity: health.SeverityOK,
},
WorkspaceProxyReport: healthcheck.WorkspaceProxyReport{
Healthy: true,
Warnings: []string{"foobar"},
Severity: health.SeverityWarning,
},
},
severity: health.SeverityWarning,
healthy: true,
failingSections: []string{},
}, { }, {
name: "AllFail", name: "AllFail",
healthy: false, healthy: false,

View File

@ -2,8 +2,9 @@ package healthcheck
import ( import (
"context" "context"
"errors" "fmt"
"sort" "sort"
"strings"
"golang.org/x/xerrors" "golang.org/x/xerrors"
@ -78,6 +79,7 @@ func (r *WorkspaceProxyReport) Run(ctx context.Context, opts *WorkspaceProxyRepo
}) })
var total, healthy int var total, healthy int
var errs []string
for _, proxy := range r.WorkspaceProxies.Regions { for _, proxy := range r.WorkspaceProxies.Regions {
total++ total++
if proxy.Healthy { if proxy.Healthy {
@ -86,34 +88,40 @@ func (r *WorkspaceProxyReport) Run(ctx context.Context, opts *WorkspaceProxyRepo
if len(proxy.Status.Report.Errors) > 0 { if len(proxy.Status.Report.Errors) > 0 {
for _, err := range proxy.Status.Report.Errors { for _, err := range proxy.Status.Report.Errors {
r.appendError(xerrors.New(err)) errs = append(errs, fmt.Sprintf("%s: %s", proxy.Name, err))
} }
} }
} }
r.Severity = calculateSeverity(total, healthy) r.Severity = calculateSeverity(total, healthy)
r.Healthy = r.Severity.Value() < health.SeverityError.Value() r.Healthy = r.Severity.Value() < health.SeverityError.Value()
switch r.Severity {
case health.SeverityWarning, health.SeverityOK:
r.Warnings = append(r.Warnings, errs...)
case health.SeverityError:
r.appendError(errs...)
}
// Versions _must_ match. Perform this check last. This will clobber any other severity. // Versions _must_ match. Perform this check last. This will clobber any other severity.
for _, proxy := range r.WorkspaceProxies.Regions { for _, proxy := range r.WorkspaceProxies.Regions {
if vErr := checkVersion(proxy, opts.CurrentVersion); vErr != nil { if vErr := checkVersion(proxy, opts.CurrentVersion); vErr != nil {
r.Healthy = false r.Healthy = false
r.Severity = health.SeverityError r.Severity = health.SeverityError
r.appendError(vErr) r.appendError(fmt.Sprintf("%s: %s", proxy.Name, vErr.Error()))
} }
} }
} }
// appendError appends errs onto r.Error. // appendError appends errs onto r.Error.
// We only have one error, so multiple errors need to be squashed in there. // We only have one error, so multiple errors need to be squashed in there.
func (r *WorkspaceProxyReport) appendError(errs ...error) { func (r *WorkspaceProxyReport) appendError(es ...string) {
if len(errs) == 0 { if len(es) == 0 {
return return
} }
if r.Error != nil { if r.Error != nil {
errs = append([]error{xerrors.New(*r.Error)}, errs...) es = append([]string{*r.Error}, es...)
} }
r.Error = ptr.Ref(errors.Join(errs...).Error()) r.Error = ptr.Ref(strings.Join(es, "\n"))
} }
func checkVersion(proxy codersdk.WorkspaceProxy, currentVersion string) error { func checkVersion(proxy codersdk.WorkspaceProxy, currentVersion string) error {

View File

@ -9,8 +9,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"golang.org/x/xerrors"
) )
func Test_WorkspaceProxyReport_appendErrors(t *testing.T) { func Test_WorkspaceProxyReport_appendErrors(t *testing.T) {
@ -20,7 +18,7 @@ func Test_WorkspaceProxyReport_appendErrors(t *testing.T) {
name string name string
expected string expected string
prevErr string prevErr string
errs []error errs []string
}{ }{
{ {
name: "nil", name: "nil",
@ -29,24 +27,24 @@ func Test_WorkspaceProxyReport_appendErrors(t *testing.T) {
{ {
name: "one error", name: "one error",
expected: assert.AnError.Error(), expected: assert.AnError.Error(),
errs: []error{assert.AnError}, errs: []string{assert.AnError.Error()},
}, },
{ {
name: "one error, one prev", name: "one error, one prev",
prevErr: "previous error", prevErr: "previous error",
expected: "previous error\n" + assert.AnError.Error(), expected: "previous error\n" + assert.AnError.Error(),
errs: []error{assert.AnError}, errs: []string{assert.AnError.Error()},
}, },
{ {
name: "two errors", name: "two errors",
expected: assert.AnError.Error() + "\nanother error", expected: assert.AnError.Error() + "\nanother error",
errs: []error{assert.AnError, xerrors.Errorf("another error")}, errs: []string{assert.AnError.Error(), "another error"},
}, },
{ {
name: "two errors, one prev", name: "two errors, one prev",
prevErr: "previous error", prevErr: "previous error",
expected: "previous error\n" + assert.AnError.Error() + "\nanother error", expected: "previous error\n" + assert.AnError.Error() + "\nanother error",
errs: []error{assert.AnError, xerrors.Errorf("another error")}, errs: []string{assert.AnError.Error(), "another error"},
}, },
} { } {
tt := tt tt := tt

View File

@ -19,14 +19,106 @@ type Story = StoryObj<typeof HealthPageView>;
export const Example: Story = {}; export const Example: Story = {};
export const AccessURLUnhealthy: Story = {
args: {
healthStatus: {
...MockHealth,
healthy: false,
severity: "error",
access_url: {
...MockHealth.access_url,
healthy: false,
error: "ouch",
},
},
},
};
export const AccessURLWarning: Story = {
args: {
healthStatus: {
...MockHealth,
healthy: true,
severity: "warning",
access_url: {
...MockHealth.access_url,
healthy: true,
warnings: ["foobar"],
},
},
},
};
export const DatabaseUnhealthy: Story = {
args: {
healthStatus: {
...MockHealth,
healthy: false,
severity: "error",
database: {
...MockHealth.database,
healthy: false,
error: "ouch",
},
},
},
};
export const DatabaseWarning: Story = {
args: {
healthStatus: {
...MockHealth,
healthy: true,
severity: "warning",
database: {
...MockHealth.database,
healthy: true,
warnings: ["foobar"],
},
},
},
};
export const WebsocketUnhealthy: Story = {
args: {
healthStatus: {
...MockHealth,
healthy: false,
severity: "error",
websocket: {
...MockHealth.websocket,
healthy: false,
error: "ouch",
},
},
},
};
export const WebsocketWarning: Story = {
args: {
healthStatus: {
...MockHealth,
healthy: true,
severity: "warning",
websocket: {
...MockHealth.websocket,
healthy: true,
warnings: ["foobar"],
},
},
},
};
export const UnhealthyDERP: Story = { export const UnhealthyDERP: Story = {
args: { args: {
healthStatus: { healthStatus: {
...MockHealth, ...MockHealth,
healthy: false, healthy: false,
severity: "error",
derp: { derp: {
...MockHealth.derp, ...MockHealth.derp,
healthy: false, healthy: false,
error: "ouch",
}, },
}, },
}, },
@ -36,6 +128,7 @@ export const DERPWarnings: Story = {
args: { args: {
healthStatus: { healthStatus: {
...MockHealth, ...MockHealth,
severity: "warning",
derp: { derp: {
...MockHealth.derp, ...MockHealth.derp,
warnings: ["foobar"], warnings: ["foobar"],
@ -43,3 +136,31 @@ export const DERPWarnings: Story = {
}, },
}, },
}; };
export const ProxyUnhealthy: Story = {
args: {
healthStatus: {
...MockHealth,
severity: "error",
healthy: false,
workspace_proxy: {
...MockHealth.workspace_proxy,
healthy: false,
error: "ouch",
},
},
},
};
export const ProxyWarning: Story = {
args: {
healthStatus: {
...MockHealth,
severity: "warning",
workspace_proxy: {
...MockHealth.workspace_proxy,
warnings: ["foobar"],
},
},
},
};

View File

@ -29,6 +29,7 @@ const sections = {
access_url: "Access URL", access_url: "Access URL",
websocket: "Websocket", websocket: "Websocket",
database: "Database", database: "Database",
workspace_proxy: "Workspace Proxy",
} as const; } as const;
export default function HealthPage() { export default function HealthPage() {