mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: do not fail DERP healthcheck if WebSocket is used (#10714)
This commit is contained in:
Generated
+36
@@ -12115,6 +12115,12 @@ const docTemplate = `{
|
||||
},
|
||||
"uses_websocket": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"warnings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -12135,6 +12141,12 @@ const docTemplate = `{
|
||||
},
|
||||
"region": {
|
||||
"$ref": "#/definitions/tailcfg.DERPRegion"
|
||||
},
|
||||
"warnings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -12164,6 +12176,12 @@ const docTemplate = `{
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/derphealth.RegionReport"
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -12201,6 +12219,12 @@ const docTemplate = `{
|
||||
},
|
||||
"status_code": {
|
||||
"type": "integer"
|
||||
},
|
||||
"warnings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -12224,6 +12248,12 @@ const docTemplate = `{
|
||||
},
|
||||
"threshold_ms": {
|
||||
"type": "integer"
|
||||
},
|
||||
"warnings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -12277,6 +12307,12 @@ const docTemplate = `{
|
||||
},
|
||||
"healthy": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"warnings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Generated
+36
@@ -11036,6 +11036,12 @@
|
||||
},
|
||||
"uses_websocket": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"warnings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -11056,6 +11062,12 @@
|
||||
},
|
||||
"region": {
|
||||
"$ref": "#/definitions/tailcfg.DERPRegion"
|
||||
},
|
||||
"warnings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -11085,6 +11097,12 @@
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/derphealth.RegionReport"
|
||||
}
|
||||
},
|
||||
"warnings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -11122,6 +11140,12 @@
|
||||
},
|
||||
"status_code": {
|
||||
"type": "integer"
|
||||
},
|
||||
"warnings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -11145,6 +11169,12 @@
|
||||
},
|
||||
"threshold_ms": {
|
||||
"type": "integer"
|
||||
},
|
||||
"warnings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -11198,6 +11228,12 @@
|
||||
},
|
||||
"healthy": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"warnings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14,8 +14,10 @@ import (
|
||||
|
||||
// @typescript-generate AccessURLReport
|
||||
type AccessURLReport struct {
|
||||
Healthy bool `json:"healthy"`
|
||||
Warnings []string `json:"warnings"`
|
||||
|
||||
AccessURL string `json:"access_url"`
|
||||
Healthy bool `json:"healthy"`
|
||||
Reachable bool `json:"reachable"`
|
||||
StatusCode int `json:"status_code"`
|
||||
HealthzResponse string `json:"healthz_response"`
|
||||
|
||||
@@ -16,7 +16,9 @@ const (
|
||||
|
||||
// @typescript-generate DatabaseReport
|
||||
type DatabaseReport struct {
|
||||
Healthy bool `json:"healthy"`
|
||||
Healthy bool `json:"healthy"`
|
||||
Warnings []string `json:"warnings"`
|
||||
|
||||
Reachable bool `json:"reachable"`
|
||||
Latency string `json:"latency"`
|
||||
LatencyMS int64 `json:"latency_ms"`
|
||||
|
||||
@@ -24,9 +24,14 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/util/ptr"
|
||||
)
|
||||
|
||||
const (
|
||||
warningNodeUsesWebsocket = `Node uses WebSockets because the "Upgrade: DERP" header may be blocked on the load balancer.`
|
||||
)
|
||||
|
||||
// @typescript-generate Report
|
||||
type Report struct {
|
||||
Healthy bool `json:"healthy"`
|
||||
Healthy bool `json:"healthy"`
|
||||
Warnings []string `json:"warnings"`
|
||||
|
||||
Regions map[int]*RegionReport `json:"regions"`
|
||||
|
||||
@@ -39,8 +44,9 @@ type Report struct {
|
||||
|
||||
// @typescript-generate RegionReport
|
||||
type RegionReport struct {
|
||||
mu sync.Mutex
|
||||
Healthy bool `json:"healthy"`
|
||||
mu sync.Mutex
|
||||
Healthy bool `json:"healthy"`
|
||||
Warnings []string `json:"warnings"`
|
||||
|
||||
Region *tailcfg.DERPRegion `json:"region"`
|
||||
NodeReports []*NodeReport `json:"node_reports"`
|
||||
@@ -52,8 +58,10 @@ type NodeReport struct {
|
||||
mu sync.Mutex
|
||||
clientCounter int
|
||||
|
||||
Healthy bool `json:"healthy"`
|
||||
Node *tailcfg.DERPNode `json:"node"`
|
||||
Healthy bool `json:"healthy"`
|
||||
Warnings []string `json:"warnings"`
|
||||
|
||||
Node *tailcfg.DERPNode `json:"node"`
|
||||
|
||||
ServerInfo derp.ServerInfoMessage `json:"node_info"`
|
||||
CanExchangeMessages bool `json:"can_exchange_messages"`
|
||||
@@ -108,6 +116,10 @@ func (r *Report) Run(ctx context.Context, opts *ReportOptions) {
|
||||
if !regionReport.Healthy {
|
||||
r.Healthy = false
|
||||
}
|
||||
|
||||
for _, w := range regionReport.Warnings {
|
||||
r.Warnings = append(r.Warnings, fmt.Sprintf("[%s] %s", regionReport.Region.RegionName, w))
|
||||
}
|
||||
mu.Unlock()
|
||||
}()
|
||||
}
|
||||
@@ -159,6 +171,10 @@ func (r *RegionReport) Run(ctx context.Context) {
|
||||
if !nodeReport.Healthy {
|
||||
r.Healthy = false
|
||||
}
|
||||
|
||||
for _, w := range nodeReport.Warnings {
|
||||
r.Warnings = append(r.Warnings, fmt.Sprintf("[%s] %s", nodeReport.Node.Name, w))
|
||||
}
|
||||
r.mu.Unlock()
|
||||
}()
|
||||
}
|
||||
@@ -208,14 +224,14 @@ func (r *NodeReport) Run(ctx context.Context) {
|
||||
|
||||
// We can't exchange messages with the node,
|
||||
if (!r.CanExchangeMessages && !r.Node.STUNOnly) ||
|
||||
// A node may use websockets because `Upgrade: DERP` may be blocked on
|
||||
// the load balancer. This is unhealthy because websockets are slower
|
||||
// than the regular DERP protocol.
|
||||
r.UsesWebsocket ||
|
||||
// The node was marked as STUN compatible but the STUN test failed.
|
||||
r.STUN.Error != nil {
|
||||
r.Healthy = false
|
||||
}
|
||||
|
||||
if r.UsesWebsocket {
|
||||
r.Warnings = append(r.Warnings, warningNodeUsesWebsocket)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *NodeReport) doExchangeMessage(ctx context.Context) {
|
||||
|
||||
@@ -170,11 +170,14 @@ func TestDERP(t *testing.T) {
|
||||
|
||||
report.Run(ctx, opts)
|
||||
|
||||
assert.False(t, report.Healthy)
|
||||
assert.True(t, report.Healthy)
|
||||
assert.NotEmpty(t, report.Warnings)
|
||||
for _, region := range report.Regions {
|
||||
assert.False(t, region.Healthy)
|
||||
assert.True(t, region.Healthy)
|
||||
assert.NotEmpty(t, region.Warnings)
|
||||
for _, node := range region.NodeReports {
|
||||
assert.False(t, node.Healthy)
|
||||
assert.True(t, node.Healthy)
|
||||
assert.NotEmpty(t, node.Warnings)
|
||||
assert.True(t, node.CanExchangeMessages)
|
||||
assert.NotEmpty(t, node.RoundTripPing)
|
||||
assert.Len(t, node.ClientLogs, 2)
|
||||
|
||||
@@ -77,6 +77,25 @@ func TestHealthcheck(t *testing.T) {
|
||||
},
|
||||
healthy: false,
|
||||
failingSections: []string{healthcheck.SectionDERP},
|
||||
}, {
|
||||
name: "DERPWarning",
|
||||
checker: &testChecker{
|
||||
DERPReport: derphealth.Report{
|
||||
Healthy: true,
|
||||
Warnings: []string{"foobar"},
|
||||
},
|
||||
AccessURLReport: healthcheck.AccessURLReport{
|
||||
Healthy: true,
|
||||
},
|
||||
WebsocketReport: healthcheck.WebsocketReport{
|
||||
Healthy: true,
|
||||
},
|
||||
DatabaseReport: healthcheck.DatabaseReport{
|
||||
Healthy: true,
|
||||
},
|
||||
},
|
||||
healthy: true,
|
||||
failingSections: nil,
|
||||
}, {
|
||||
name: "AccessURLFail",
|
||||
checker: &testChecker{
|
||||
@@ -153,6 +172,7 @@ func TestHealthcheck(t *testing.T) {
|
||||
assert.Equal(t, c.healthy, report.Healthy)
|
||||
assert.Equal(t, c.failingSections, report.FailingSections)
|
||||
assert.Equal(t, c.checker.DERPReport.Healthy, report.DERP.Healthy)
|
||||
assert.Equal(t, c.checker.DERPReport.Warnings, report.DERP.Warnings)
|
||||
assert.Equal(t, c.checker.AccessURLReport.Healthy, report.AccessURL.Healthy)
|
||||
assert.Equal(t, c.checker.WebsocketReport.Healthy, report.Websocket.Healthy)
|
||||
assert.NotZero(t, report.Time)
|
||||
|
||||
@@ -21,10 +21,12 @@ type WebsocketReportOptions struct {
|
||||
|
||||
// @typescript-generate WebsocketReport
|
||||
type WebsocketReport struct {
|
||||
Healthy bool `json:"healthy"`
|
||||
Body string `json:"body"`
|
||||
Code int `json:"code"`
|
||||
Error *string `json:"error"`
|
||||
Healthy bool `json:"healthy"`
|
||||
Warnings []string `json:"warnings"`
|
||||
|
||||
Body string `json:"body"`
|
||||
Code int `json:"code"`
|
||||
Error *string `json:"error"`
|
||||
}
|
||||
|
||||
func (r *WebsocketReport) Run(ctx context.Context, opts *WebsocketReportOptions) {
|
||||
|
||||
Generated
+16
-8
@@ -51,7 +51,8 @@ curl -X GET http://coder-server:8080/api/v2/debug/health \
|
||||
"healthy": true,
|
||||
"healthz_response": "string",
|
||||
"reachable": true,
|
||||
"status_code": 0
|
||||
"status_code": 0,
|
||||
"warnings": ["string"]
|
||||
},
|
||||
"coder_version": "string",
|
||||
"database": {
|
||||
@@ -60,7 +61,8 @@ curl -X GET http://coder-server:8080/api/v2/debug/health \
|
||||
"latency": "string",
|
||||
"latency_ms": 0,
|
||||
"reachable": true,
|
||||
"threshold_ms": 0
|
||||
"threshold_ms": 0,
|
||||
"warnings": ["string"]
|
||||
},
|
||||
"derp": {
|
||||
"error": "string",
|
||||
@@ -134,7 +136,8 @@ curl -X GET http://coder-server:8080/api/v2/debug/health \
|
||||
"enabled": true,
|
||||
"error": "string"
|
||||
},
|
||||
"uses_websocket": true
|
||||
"uses_websocket": true,
|
||||
"warnings": ["string"]
|
||||
}
|
||||
],
|
||||
"region": {
|
||||
@@ -160,7 +163,8 @@ curl -X GET http://coder-server:8080/api/v2/debug/health \
|
||||
"regionCode": "string",
|
||||
"regionID": 0,
|
||||
"regionName": "string"
|
||||
}
|
||||
},
|
||||
"warnings": ["string"]
|
||||
},
|
||||
"property2": {
|
||||
"error": "string",
|
||||
@@ -198,7 +202,8 @@ curl -X GET http://coder-server:8080/api/v2/debug/health \
|
||||
"enabled": true,
|
||||
"error": "string"
|
||||
},
|
||||
"uses_websocket": true
|
||||
"uses_websocket": true,
|
||||
"warnings": ["string"]
|
||||
}
|
||||
],
|
||||
"region": {
|
||||
@@ -224,9 +229,11 @@ curl -X GET http://coder-server:8080/api/v2/debug/health \
|
||||
"regionCode": "string",
|
||||
"regionID": 0,
|
||||
"regionName": "string"
|
||||
}
|
||||
},
|
||||
"warnings": ["string"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"warnings": ["string"]
|
||||
},
|
||||
"failing_sections": ["string"],
|
||||
"healthy": true,
|
||||
@@ -235,7 +242,8 @@ curl -X GET http://coder-server:8080/api/v2/debug/health \
|
||||
"body": "string",
|
||||
"code": 0,
|
||||
"error": "string",
|
||||
"healthy": true
|
||||
"healthy": true,
|
||||
"warnings": ["string"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Generated
+66
-41
@@ -7138,7 +7138,8 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
"enabled": true,
|
||||
"error": "string"
|
||||
},
|
||||
"uses_websocket": true
|
||||
"uses_websocket": true,
|
||||
"warnings": ["string"]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -7157,6 +7158,7 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
| `round_trip_ping_ms` | integer | false | | |
|
||||
| `stun` | [derphealth.StunReport](#derphealthstunreport) | false | | |
|
||||
| `uses_websocket` | boolean | false | | |
|
||||
| `warnings` | array of string | false | | |
|
||||
|
||||
## derphealth.RegionReport
|
||||
|
||||
@@ -7197,7 +7199,8 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
"enabled": true,
|
||||
"error": "string"
|
||||
},
|
||||
"uses_websocket": true
|
||||
"uses_websocket": true,
|
||||
"warnings": ["string"]
|
||||
}
|
||||
],
|
||||
"region": {
|
||||
@@ -7223,7 +7226,8 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
"regionCode": "string",
|
||||
"regionID": 0,
|
||||
"regionName": "string"
|
||||
}
|
||||
},
|
||||
"warnings": ["string"]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -7235,6 +7239,7 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
| `healthy` | boolean | false | | |
|
||||
| `node_reports` | array of [derphealth.NodeReport](#derphealthnodereport) | false | | |
|
||||
| `region` | [tailcfg.DERPRegion](#tailcfgderpregion) | false | | |
|
||||
| `warnings` | array of string | false | | |
|
||||
|
||||
## derphealth.Report
|
||||
|
||||
@@ -7311,7 +7316,8 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
"enabled": true,
|
||||
"error": "string"
|
||||
},
|
||||
"uses_websocket": true
|
||||
"uses_websocket": true,
|
||||
"warnings": ["string"]
|
||||
}
|
||||
],
|
||||
"region": {
|
||||
@@ -7337,7 +7343,8 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
"regionCode": "string",
|
||||
"regionID": 0,
|
||||
"regionName": "string"
|
||||
}
|
||||
},
|
||||
"warnings": ["string"]
|
||||
},
|
||||
"property2": {
|
||||
"error": "string",
|
||||
@@ -7375,7 +7382,8 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
"enabled": true,
|
||||
"error": "string"
|
||||
},
|
||||
"uses_websocket": true
|
||||
"uses_websocket": true,
|
||||
"warnings": ["string"]
|
||||
}
|
||||
],
|
||||
"region": {
|
||||
@@ -7401,9 +7409,11 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
"regionCode": "string",
|
||||
"regionID": 0,
|
||||
"regionName": "string"
|
||||
}
|
||||
},
|
||||
"warnings": ["string"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"warnings": ["string"]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -7418,6 +7428,7 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
| `netcheck_logs` | array of string | false | | |
|
||||
| `regions` | object | false | | |
|
||||
| » `[any property]` | [derphealth.RegionReport](#derphealthregionreport) | false | | |
|
||||
| `warnings` | array of string | false | | |
|
||||
|
||||
## derphealth.StunReport
|
||||
|
||||
@@ -7446,20 +7457,22 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
"healthy": true,
|
||||
"healthz_response": "string",
|
||||
"reachable": true,
|
||||
"status_code": 0
|
||||
"status_code": 0,
|
||||
"warnings": ["string"]
|
||||
}
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| ------------------ | ------- | -------- | ------------ | ----------- |
|
||||
| `access_url` | string | false | | |
|
||||
| `error` | string | false | | |
|
||||
| `healthy` | boolean | false | | |
|
||||
| `healthz_response` | string | false | | |
|
||||
| `reachable` | boolean | false | | |
|
||||
| `status_code` | integer | false | | |
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| ------------------ | --------------- | -------- | ------------ | ----------- |
|
||||
| `access_url` | string | false | | |
|
||||
| `error` | string | false | | |
|
||||
| `healthy` | boolean | false | | |
|
||||
| `healthz_response` | string | false | | |
|
||||
| `reachable` | boolean | false | | |
|
||||
| `status_code` | integer | false | | |
|
||||
| `warnings` | array of string | false | | |
|
||||
|
||||
## healthcheck.DatabaseReport
|
||||
|
||||
@@ -7470,20 +7483,22 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
"latency": "string",
|
||||
"latency_ms": 0,
|
||||
"reachable": true,
|
||||
"threshold_ms": 0
|
||||
"threshold_ms": 0,
|
||||
"warnings": ["string"]
|
||||
}
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| -------------- | ------- | -------- | ------------ | ----------- |
|
||||
| `error` | string | false | | |
|
||||
| `healthy` | boolean | false | | |
|
||||
| `latency` | string | false | | |
|
||||
| `latency_ms` | integer | false | | |
|
||||
| `reachable` | boolean | false | | |
|
||||
| `threshold_ms` | integer | false | | |
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| -------------- | --------------- | -------- | ------------ | ----------- |
|
||||
| `error` | string | false | | |
|
||||
| `healthy` | boolean | false | | |
|
||||
| `latency` | string | false | | |
|
||||
| `latency_ms` | integer | false | | |
|
||||
| `reachable` | boolean | false | | |
|
||||
| `threshold_ms` | integer | false | | |
|
||||
| `warnings` | array of string | false | | |
|
||||
|
||||
## healthcheck.Report
|
||||
|
||||
@@ -7495,7 +7510,8 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
"healthy": true,
|
||||
"healthz_response": "string",
|
||||
"reachable": true,
|
||||
"status_code": 0
|
||||
"status_code": 0,
|
||||
"warnings": ["string"]
|
||||
},
|
||||
"coder_version": "string",
|
||||
"database": {
|
||||
@@ -7504,7 +7520,8 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
"latency": "string",
|
||||
"latency_ms": 0,
|
||||
"reachable": true,
|
||||
"threshold_ms": 0
|
||||
"threshold_ms": 0,
|
||||
"warnings": ["string"]
|
||||
},
|
||||
"derp": {
|
||||
"error": "string",
|
||||
@@ -7578,7 +7595,8 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
"enabled": true,
|
||||
"error": "string"
|
||||
},
|
||||
"uses_websocket": true
|
||||
"uses_websocket": true,
|
||||
"warnings": ["string"]
|
||||
}
|
||||
],
|
||||
"region": {
|
||||
@@ -7604,7 +7622,8 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
"regionCode": "string",
|
||||
"regionID": 0,
|
||||
"regionName": "string"
|
||||
}
|
||||
},
|
||||
"warnings": ["string"]
|
||||
},
|
||||
"property2": {
|
||||
"error": "string",
|
||||
@@ -7642,7 +7661,8 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
"enabled": true,
|
||||
"error": "string"
|
||||
},
|
||||
"uses_websocket": true
|
||||
"uses_websocket": true,
|
||||
"warnings": ["string"]
|
||||
}
|
||||
],
|
||||
"region": {
|
||||
@@ -7668,9 +7688,11 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
"regionCode": "string",
|
||||
"regionID": 0,
|
||||
"regionName": "string"
|
||||
}
|
||||
},
|
||||
"warnings": ["string"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"warnings": ["string"]
|
||||
},
|
||||
"failing_sections": ["string"],
|
||||
"healthy": true,
|
||||
@@ -7679,7 +7701,8 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
"body": "string",
|
||||
"code": 0,
|
||||
"error": "string",
|
||||
"healthy": true
|
||||
"healthy": true,
|
||||
"warnings": ["string"]
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -7704,18 +7727,20 @@ If the schedule is empty, the user will be updated to use the default schedule.|
|
||||
"body": "string",
|
||||
"code": 0,
|
||||
"error": "string",
|
||||
"healthy": true
|
||||
"healthy": true,
|
||||
"warnings": ["string"]
|
||||
}
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| --------- | ------- | -------- | ------------ | ----------- |
|
||||
| `body` | string | false | | |
|
||||
| `code` | integer | false | | |
|
||||
| `error` | string | false | | |
|
||||
| `healthy` | boolean | false | | |
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| ---------- | --------------- | -------- | ------------ | ----------- |
|
||||
| `body` | string | false | | |
|
||||
| `code` | integer | false | | |
|
||||
| `error` | string | false | | |
|
||||
| `healthy` | boolean | false | | |
|
||||
| `warnings` | array of string | false | | |
|
||||
|
||||
## netcheck.Report
|
||||
|
||||
|
||||
Generated
+7
-1
@@ -2081,8 +2081,9 @@ export type RegionTypes = Region | WorkspaceProxy;
|
||||
|
||||
// From healthcheck/accessurl.go
|
||||
export interface HealthcheckAccessURLReport {
|
||||
readonly access_url: string;
|
||||
readonly healthy: boolean;
|
||||
readonly warnings: string[];
|
||||
readonly access_url: string;
|
||||
readonly reachable: boolean;
|
||||
readonly status_code: number;
|
||||
readonly healthz_response: string;
|
||||
@@ -2092,6 +2093,7 @@ export interface HealthcheckAccessURLReport {
|
||||
// From healthcheck/database.go
|
||||
export interface HealthcheckDatabaseReport {
|
||||
readonly healthy: boolean;
|
||||
readonly warnings: string[];
|
||||
readonly reachable: boolean;
|
||||
readonly latency: string;
|
||||
readonly latency_ms: number;
|
||||
@@ -2114,6 +2116,7 @@ export interface HealthcheckReport {
|
||||
// From healthcheck/websocket.go
|
||||
export interface HealthcheckWebsocketReport {
|
||||
readonly healthy: boolean;
|
||||
readonly warnings: string[];
|
||||
readonly body: string;
|
||||
readonly code: number;
|
||||
readonly error?: string;
|
||||
@@ -2169,6 +2172,7 @@ export const ClibaseValueSources: ClibaseValueSource[] = [
|
||||
// From derphealth/derp.go
|
||||
export interface DerphealthNodeReport {
|
||||
readonly healthy: boolean;
|
||||
readonly warnings: string[];
|
||||
// Named type "tailscale.com/tailcfg.DERPNode" unknown, using "any"
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- External type
|
||||
readonly node?: any;
|
||||
@@ -2188,6 +2192,7 @@ export interface DerphealthNodeReport {
|
||||
// From derphealth/derp.go
|
||||
export interface DerphealthRegionReport {
|
||||
readonly healthy: boolean;
|
||||
readonly warnings: string[];
|
||||
// Named type "tailscale.com/tailcfg.DERPRegion" unknown, using "any"
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- External type
|
||||
readonly region?: any;
|
||||
@@ -2198,6 +2203,7 @@ export interface DerphealthRegionReport {
|
||||
// From derphealth/derp.go
|
||||
export interface DerphealthReport {
|
||||
readonly healthy: boolean;
|
||||
readonly warnings: string[];
|
||||
readonly regions: Record<number, DerphealthRegionReport>;
|
||||
// Named type "tailscale.com/net/netcheck.Report" unknown, using "any"
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- External type
|
||||
|
||||
@@ -31,3 +31,15 @@ export const UnhealthyDERP: Story = {
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const DERPWarnings: Story = {
|
||||
args: {
|
||||
healthStatus: {
|
||||
...MockHealth,
|
||||
derp: {
|
||||
...MockHealth.derp,
|
||||
warnings: ["foobar"],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -85,7 +85,13 @@ export function HealthPageView({
|
||||
</PageHeaderTitle>
|
||||
<PageHeaderSubtitle>
|
||||
{healthStatus.healthy
|
||||
? "All systems operational"
|
||||
? Object.keys(sections).some(
|
||||
(key) =>
|
||||
healthStatus[key as keyof typeof sections]?.warnings
|
||||
.length > 0,
|
||||
)
|
||||
? "All systems operational, but performance might be degraded"
|
||||
: "All systems operational"
|
||||
: "Some issues have been detected"}
|
||||
</PageHeaderSubtitle>
|
||||
</div>
|
||||
@@ -137,9 +143,10 @@ export function HealthPageView({
|
||||
.map((key) => {
|
||||
const label = sections[key as keyof typeof sections];
|
||||
const isActive = tab.value === key;
|
||||
const isHealthy =
|
||||
healthStatus[key as keyof typeof sections].healthy;
|
||||
|
||||
const healthSection =
|
||||
healthStatus[key as keyof typeof sections];
|
||||
const isHealthy = healthSection.healthy;
|
||||
const isWarning = healthSection.warnings.length > 0;
|
||||
return (
|
||||
<Box
|
||||
component="button"
|
||||
@@ -171,13 +178,23 @@ export function HealthPageView({
|
||||
}}
|
||||
>
|
||||
{isHealthy ? (
|
||||
<CheckCircleOutlined
|
||||
sx={{
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: (theme) => theme.palette.success.light,
|
||||
}}
|
||||
/>
|
||||
isWarning ? (
|
||||
<CheckCircleOutlined
|
||||
sx={{
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: (theme) => theme.palette.warning.main,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<CheckCircleOutlined
|
||||
sx={{
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: (theme) => theme.palette.success.light,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<ErrorOutline
|
||||
sx={{
|
||||
|
||||
@@ -2376,9 +2376,11 @@ export const MockHealth: TypesGen.HealthcheckReport = {
|
||||
failing_sections: [],
|
||||
derp: {
|
||||
healthy: true,
|
||||
warnings: [],
|
||||
regions: {
|
||||
"999": {
|
||||
healthy: true,
|
||||
warnings: [],
|
||||
region: {
|
||||
EmbeddedRelay: true,
|
||||
RegionID: 999,
|
||||
@@ -2404,6 +2406,7 @@ export const MockHealth: TypesGen.HealthcheckReport = {
|
||||
node_reports: [
|
||||
{
|
||||
healthy: true,
|
||||
warnings: [],
|
||||
node: {
|
||||
Name: "999stun0",
|
||||
RegionID: 999,
|
||||
@@ -2428,6 +2431,7 @@ export const MockHealth: TypesGen.HealthcheckReport = {
|
||||
},
|
||||
{
|
||||
healthy: true,
|
||||
warnings: [],
|
||||
node: {
|
||||
Name: "999b",
|
||||
RegionID: 999,
|
||||
@@ -2461,6 +2465,7 @@ export const MockHealth: TypesGen.HealthcheckReport = {
|
||||
},
|
||||
"10007": {
|
||||
healthy: true,
|
||||
warnings: [],
|
||||
region: {
|
||||
EmbeddedRelay: false,
|
||||
RegionID: 10007,
|
||||
@@ -2486,6 +2491,7 @@ export const MockHealth: TypesGen.HealthcheckReport = {
|
||||
node_reports: [
|
||||
{
|
||||
healthy: true,
|
||||
warnings: [],
|
||||
node: {
|
||||
Name: "10007stun0",
|
||||
RegionID: 10007,
|
||||
@@ -2510,6 +2516,7 @@ export const MockHealth: TypesGen.HealthcheckReport = {
|
||||
},
|
||||
{
|
||||
healthy: true,
|
||||
warnings: [],
|
||||
node: {
|
||||
Name: "10007a",
|
||||
RegionID: 10007,
|
||||
@@ -2543,6 +2550,7 @@ export const MockHealth: TypesGen.HealthcheckReport = {
|
||||
},
|
||||
"10008": {
|
||||
healthy: true,
|
||||
warnings: [],
|
||||
region: {
|
||||
EmbeddedRelay: false,
|
||||
RegionID: 10008,
|
||||
@@ -2568,6 +2576,7 @@ export const MockHealth: TypesGen.HealthcheckReport = {
|
||||
node_reports: [
|
||||
{
|
||||
healthy: true,
|
||||
warnings: [],
|
||||
node: {
|
||||
Name: "10008stun0",
|
||||
RegionID: 10008,
|
||||
@@ -2592,6 +2601,7 @@ export const MockHealth: TypesGen.HealthcheckReport = {
|
||||
},
|
||||
{
|
||||
healthy: true,
|
||||
warnings: [],
|
||||
node: {
|
||||
Name: "10008a",
|
||||
RegionID: 10008,
|
||||
@@ -2625,6 +2635,7 @@ export const MockHealth: TypesGen.HealthcheckReport = {
|
||||
},
|
||||
"10009": {
|
||||
healthy: true,
|
||||
warnings: [],
|
||||
region: {
|
||||
EmbeddedRelay: false,
|
||||
RegionID: 10009,
|
||||
@@ -2650,6 +2661,7 @@ export const MockHealth: TypesGen.HealthcheckReport = {
|
||||
node_reports: [
|
||||
{
|
||||
healthy: true,
|
||||
warnings: [],
|
||||
node: {
|
||||
Name: "10009stun0",
|
||||
RegionID: 10009,
|
||||
@@ -2674,6 +2686,7 @@ export const MockHealth: TypesGen.HealthcheckReport = {
|
||||
},
|
||||
{
|
||||
healthy: true,
|
||||
warnings: [],
|
||||
node: {
|
||||
Name: "10009a",
|
||||
RegionID: 10009,
|
||||
@@ -2751,19 +2764,22 @@ export const MockHealth: TypesGen.HealthcheckReport = {
|
||||
],
|
||||
},
|
||||
access_url: {
|
||||
access_url: "https://dev.coder.com",
|
||||
healthy: true,
|
||||
warnings: [],
|
||||
access_url: "https://dev.coder.com",
|
||||
reachable: true,
|
||||
status_code: 200,
|
||||
healthz_response: "OK",
|
||||
},
|
||||
websocket: {
|
||||
healthy: true,
|
||||
warnings: [],
|
||||
body: "",
|
||||
code: 101,
|
||||
},
|
||||
database: {
|
||||
healthy: true,
|
||||
warnings: [],
|
||||
reachable: true,
|
||||
latency: "92570",
|
||||
latency_ms: 92570,
|
||||
@@ -2788,6 +2804,7 @@ export const DeploymentHealthUnhealthy: TypesGen.HealthcheckReport = {
|
||||
coder_version: "v2.3.0-devel+8cca4915a",
|
||||
access_url: {
|
||||
healthy: true,
|
||||
warnings: [],
|
||||
access_url: "",
|
||||
healthz_response: "",
|
||||
reachable: true,
|
||||
@@ -2795,6 +2812,7 @@ export const DeploymentHealthUnhealthy: TypesGen.HealthcheckReport = {
|
||||
},
|
||||
database: {
|
||||
healthy: false,
|
||||
warnings: [],
|
||||
latency: "",
|
||||
latency_ms: 0,
|
||||
reachable: true,
|
||||
@@ -2802,11 +2820,13 @@ export const DeploymentHealthUnhealthy: TypesGen.HealthcheckReport = {
|
||||
},
|
||||
derp: {
|
||||
healthy: false,
|
||||
warnings: [],
|
||||
regions: [],
|
||||
netcheck_logs: [],
|
||||
},
|
||||
websocket: {
|
||||
healthy: false,
|
||||
warnings: [],
|
||||
body: "",
|
||||
code: 0,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user