refactor(coderd/healthcheck): move derp report to derphealth package (#9506)

This change helps remove one indirect use of coderd/database in the slim
CLI.

No size change (yet).

Ref: #9380
This commit is contained in:
Mathias Fredriksson
2023-09-04 21:41:50 +03:00
committed by GitHub
parent a1025f92af
commit 39e3b049a5
12 changed files with 242 additions and 228 deletions

62
coderd/apidoc/docs.go generated
View File

@ -11400,30 +11400,7 @@ const docTemplate = `{
}
}
},
"healthcheck.AccessURLReport": {
"type": "object",
"properties": {
"access_url": {
"type": "string"
},
"error": {
"type": "string"
},
"healthy": {
"type": "boolean"
},
"healthz_response": {
"type": "string"
},
"reachable": {
"type": "boolean"
},
"status_code": {
"type": "integer"
}
}
},
"healthcheck.DERPNodeReport": {
"derphealth.NodeReport": {
"type": "object",
"properties": {
"can_exchange_messages": {
@ -11466,14 +11443,14 @@ const docTemplate = `{
"type": "integer"
},
"stun": {
"$ref": "#/definitions/healthcheck.DERPStunReport"
"$ref": "#/definitions/derphealth.StunReport"
},
"uses_websocket": {
"type": "boolean"
}
}
},
"healthcheck.DERPRegionReport": {
"derphealth.RegionReport": {
"type": "object",
"properties": {
"error": {
@ -11485,7 +11462,7 @@ const docTemplate = `{
"node_reports": {
"type": "array",
"items": {
"$ref": "#/definitions/healthcheck.DERPNodeReport"
"$ref": "#/definitions/derphealth.NodeReport"
}
},
"region": {
@ -11493,7 +11470,7 @@ const docTemplate = `{
}
}
},
"healthcheck.DERPReport": {
"derphealth.Report": {
"type": "object",
"properties": {
"error": {
@ -11517,12 +11494,12 @@ const docTemplate = `{
"regions": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/healthcheck.DERPRegionReport"
"$ref": "#/definitions/derphealth.RegionReport"
}
}
}
},
"healthcheck.DERPStunReport": {
"derphealth.StunReport": {
"type": "object",
"properties": {
"canSTUN": {
@ -11536,6 +11513,29 @@ const docTemplate = `{
}
}
},
"healthcheck.AccessURLReport": {
"type": "object",
"properties": {
"access_url": {
"type": "string"
},
"error": {
"type": "string"
},
"healthy": {
"type": "boolean"
},
"healthz_response": {
"type": "string"
},
"reachable": {
"type": "boolean"
},
"status_code": {
"type": "integer"
}
}
},
"healthcheck.DatabaseReport": {
"type": "object",
"properties": {
@ -11570,7 +11570,7 @@ const docTemplate = `{
"$ref": "#/definitions/healthcheck.DatabaseReport"
},
"derp": {
"$ref": "#/definitions/healthcheck.DERPReport"
"$ref": "#/definitions/derphealth.Report"
},
"failing_sections": {
"description": "FailingSections is a list of sections that have failed their healthcheck.",

View File

@ -10366,30 +10366,7 @@
}
}
},
"healthcheck.AccessURLReport": {
"type": "object",
"properties": {
"access_url": {
"type": "string"
},
"error": {
"type": "string"
},
"healthy": {
"type": "boolean"
},
"healthz_response": {
"type": "string"
},
"reachable": {
"type": "boolean"
},
"status_code": {
"type": "integer"
}
}
},
"healthcheck.DERPNodeReport": {
"derphealth.NodeReport": {
"type": "object",
"properties": {
"can_exchange_messages": {
@ -10432,14 +10409,14 @@
"type": "integer"
},
"stun": {
"$ref": "#/definitions/healthcheck.DERPStunReport"
"$ref": "#/definitions/derphealth.StunReport"
},
"uses_websocket": {
"type": "boolean"
}
}
},
"healthcheck.DERPRegionReport": {
"derphealth.RegionReport": {
"type": "object",
"properties": {
"error": {
@ -10451,7 +10428,7 @@
"node_reports": {
"type": "array",
"items": {
"$ref": "#/definitions/healthcheck.DERPNodeReport"
"$ref": "#/definitions/derphealth.NodeReport"
}
},
"region": {
@ -10459,7 +10436,7 @@
}
}
},
"healthcheck.DERPReport": {
"derphealth.Report": {
"type": "object",
"properties": {
"error": {
@ -10483,12 +10460,12 @@
"regions": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/healthcheck.DERPRegionReport"
"$ref": "#/definitions/derphealth.RegionReport"
}
}
}
},
"healthcheck.DERPStunReport": {
"derphealth.StunReport": {
"type": "object",
"properties": {
"canSTUN": {
@ -10502,6 +10479,29 @@
}
}
},
"healthcheck.AccessURLReport": {
"type": "object",
"properties": {
"access_url": {
"type": "string"
},
"error": {
"type": "string"
},
"healthy": {
"type": "boolean"
},
"healthz_response": {
"type": "string"
},
"reachable": {
"type": "boolean"
},
"status_code": {
"type": "integer"
}
}
},
"healthcheck.DatabaseReport": {
"type": "object",
"properties": {
@ -10536,7 +10536,7 @@
"$ref": "#/definitions/healthcheck.DatabaseReport"
},
"derp": {
"$ref": "#/definitions/healthcheck.DERPReport"
"$ref": "#/definitions/derphealth.Report"
},
"failing_sections": {
"description": "FailingSections is a list of sections that have failed their healthcheck.",

View File

@ -1,4 +1,4 @@
package healthcheck
package derphealth
import (
"context"
@ -24,11 +24,11 @@ import (
"github.com/coder/coder/v2/coderd/util/ptr"
)
// @typescript-generate DERPReport
type DERPReport struct {
// @typescript-generate Report
type Report struct {
Healthy bool `json:"healthy"`
Regions map[int]*DERPRegionReport `json:"regions"`
Regions map[int]*RegionReport `json:"regions"`
Netcheck *netcheck.Report `json:"netcheck"`
NetcheckErr *string `json:"netcheck_err"`
@ -37,18 +37,18 @@ type DERPReport struct {
Error *string `json:"error"`
}
// @typescript-generate DERPRegionReport
type DERPRegionReport struct {
// @typescript-generate RegionReport
type RegionReport struct {
mu sync.Mutex
Healthy bool `json:"healthy"`
Region *tailcfg.DERPRegion `json:"region"`
NodeReports []*DERPNodeReport `json:"node_reports"`
NodeReports []*NodeReport `json:"node_reports"`
Error *string `json:"error"`
}
// @typescript-generate DERPNodeReport
type DERPNodeReport struct {
// @typescript-generate NodeReport
type NodeReport struct {
mu sync.Mutex
clientCounter int
@ -64,23 +64,23 @@ type DERPNodeReport struct {
ClientErrs [][]string `json:"client_errs"`
Error *string `json:"error"`
STUN DERPStunReport `json:"stun"`
STUN StunReport `json:"stun"`
}
// @typescript-generate DERPStunReport
type DERPStunReport struct {
// @typescript-generate StunReport
type StunReport struct {
Enabled bool
CanSTUN bool
Error *string
}
type DERPReportOptions struct {
type ReportOptions struct {
DERPMap *tailcfg.DERPMap
}
func (r *DERPReport) Run(ctx context.Context, opts *DERPReportOptions) {
func (r *Report) Run(ctx context.Context, opts *ReportOptions) {
r.Healthy = true
r.Regions = map[int]*DERPRegionReport{}
r.Regions = map[int]*RegionReport{}
wg := &sync.WaitGroup{}
mu := sync.Mutex{}
@ -89,7 +89,7 @@ func (r *DERPReport) Run(ctx context.Context, opts *DERPReportOptions) {
for _, region := range opts.DERPMap.Regions {
var (
region = region
regionReport = DERPRegionReport{
regionReport = RegionReport{
Region: region,
}
)
@ -128,9 +128,9 @@ func (r *DERPReport) Run(ctx context.Context, opts *DERPReportOptions) {
wg.Wait()
}
func (r *DERPRegionReport) Run(ctx context.Context) {
func (r *RegionReport) Run(ctx context.Context) {
r.Healthy = true
r.NodeReports = []*DERPNodeReport{}
r.NodeReports = []*NodeReport{}
wg := &sync.WaitGroup{}
@ -138,7 +138,7 @@ func (r *DERPRegionReport) Run(ctx context.Context) {
for _, node := range r.Region.Nodes {
var (
node = node
nodeReport = DERPNodeReport{
nodeReport = NodeReport{
Node: node,
Healthy: true,
}
@ -166,7 +166,7 @@ func (r *DERPRegionReport) Run(ctx context.Context) {
wg.Wait()
}
func (r *DERPNodeReport) derpURL() *url.URL {
func (r *NodeReport) derpURL() *url.URL {
derpURL := &url.URL{
Scheme: "https",
Host: r.Node.HostName,
@ -185,7 +185,7 @@ func (r *DERPNodeReport) derpURL() *url.URL {
return derpURL
}
func (r *DERPNodeReport) Run(ctx context.Context) {
func (r *NodeReport) Run(ctx context.Context) {
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
@ -218,7 +218,7 @@ func (r *DERPNodeReport) Run(ctx context.Context) {
}
}
func (r *DERPNodeReport) doExchangeMessage(ctx context.Context) {
func (r *NodeReport) doExchangeMessage(ctx context.Context) {
if r.Node.STUNOnly {
return
}
@ -299,7 +299,7 @@ func (r *DERPNodeReport) doExchangeMessage(ctx context.Context) {
wg.Wait()
}
func (r *DERPNodeReport) doSTUNTest(ctx context.Context) {
func (r *NodeReport) doSTUNTest(ctx context.Context) {
if r.Node.STUNPort == -1 {
return
}
@ -331,7 +331,7 @@ func (r *DERPNodeReport) doSTUNTest(ctx context.Context) {
r.mu.Unlock()
}
func (r *DERPNodeReport) stunAddr(ctx context.Context) (string, int, error) {
func (r *NodeReport) stunAddr(ctx context.Context) (string, int, error) {
port := r.Node.STUNPort
if port == 0 {
port = 3478
@ -387,13 +387,13 @@ func (r *DERPNodeReport) stunAddr(ctx context.Context) (string, int, error) {
return "", 0, xerrors.New("no stun ips provided")
}
func (r *DERPNodeReport) writeClientErr(clientID int, err error) {
func (r *NodeReport) writeClientErr(clientID int, err error) {
r.mu.Lock()
r.ClientErrs[clientID] = append(r.ClientErrs[clientID], err.Error())
r.mu.Unlock()
}
func (r *DERPNodeReport) derpClient(ctx context.Context, derpURL *url.URL) (*derphttp.Client, int, error) {
func (r *NodeReport) derpClient(ctx context.Context, derpURL *url.URL) (*derphttp.Client, int, error) {
r.mu.Lock()
id := r.clientCounter
r.clientCounter++
@ -440,7 +440,7 @@ func (r *DERPNodeReport) derpClient(ctx context.Context, derpURL *url.URL) (*der
return client, id, nil
}
func (r *DERPNodeReport) recvData(client *derphttp.Client) (derp.ReceivedPacket, error) {
func (r *NodeReport) recvData(client *derphttp.Client) (derp.ReceivedPacket, error) {
for {
msg, err := client.Recv()
if err != nil {
@ -459,3 +459,11 @@ func (r *DERPNodeReport) recvData(client *derphttp.Client) (derp.ReceivedPacket,
}
}
}
func convertError(err error) *string {
if err != nil {
return ptr.Ref(err.Error())
}
return nil
}

View File

@ -1,4 +1,4 @@
package healthcheck_test
package derphealth_test
import (
"context"
@ -17,7 +17,7 @@ import (
"tailscale.com/tailcfg"
"tailscale.com/types/key"
"github.com/coder/coder/v2/coderd/healthcheck"
"github.com/coder/coder/v2/coderd/healthcheck/derphealth"
"github.com/coder/coder/v2/tailnet"
"github.com/coder/coder/v2/testutil"
)
@ -38,9 +38,9 @@ func TestDERP(t *testing.T) {
var (
ctx = context.Background()
report = healthcheck.DERPReport{}
report = derphealth.Report{}
derpURL, _ = url.Parse(srv.URL)
opts = &healthcheck.DERPReportOptions{
opts = &derphealth.ReportOptions{
DERPMap: &tailcfg.DERPMap{Regions: map[int]*tailcfg.DERPRegion{
1: {
EmbeddedRelay: true,
@ -95,8 +95,8 @@ func TestDERP(t *testing.T) {
var (
ctx = context.Background()
report = healthcheck.DERPReport{}
opts = &healthcheck.DERPReportOptions{
report = derphealth.Report{}
opts = &derphealth.ReportOptions{
DERPMap: tsDERPMap(ctx, t),
}
)
@ -145,9 +145,9 @@ func TestDERP(t *testing.T) {
var (
ctx = context.Background()
report = healthcheck.DERPReport{}
report = derphealth.Report{}
derpURL, _ = url.Parse(srv.URL)
opts = &healthcheck.DERPReportOptions{
opts = &derphealth.ReportOptions{
DERPMap: &tailcfg.DERPMap{Regions: map[int]*tailcfg.DERPRegion{
1: {
EmbeddedRelay: true,
@ -195,8 +195,8 @@ func TestDERP(t *testing.T) {
var (
ctx = context.Background()
report = healthcheck.DERPReport{}
opts = &healthcheck.DERPReportOptions{
report = derphealth.Report{}
opts = &derphealth.ReportOptions{
DERPMap: &tailcfg.DERPMap{Regions: map[int]*tailcfg.DERPRegion{
1: {
EmbeddedRelay: true,

View File

@ -12,6 +12,7 @@ import (
"github.com/coder/coder/v2/buildinfo"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/healthcheck/derphealth"
"github.com/coder/coder/v2/coderd/util/ptr"
)
@ -23,7 +24,7 @@ const (
)
type Checker interface {
DERP(ctx context.Context, opts *DERPReportOptions) DERPReport
DERP(ctx context.Context, opts *derphealth.ReportOptions) derphealth.Report
AccessURL(ctx context.Context, opts *AccessURLReportOptions) AccessURLReport
Websocket(ctx context.Context, opts *WebsocketReportOptions) WebsocketReport
Database(ctx context.Context, opts *DatabaseReportOptions) DatabaseReport
@ -38,10 +39,10 @@ type Report struct {
// FailingSections is a list of sections that have failed their healthcheck.
FailingSections []string `json:"failing_sections"`
DERP DERPReport `json:"derp"`
AccessURL AccessURLReport `json:"access_url"`
Websocket WebsocketReport `json:"websocket"`
Database DatabaseReport `json:"database"`
DERP derphealth.Report `json:"derp"`
AccessURL AccessURLReport `json:"access_url"`
Websocket WebsocketReport `json:"websocket"`
Database DatabaseReport `json:"database"`
// The Coder version of the server that the report was generated on.
CoderVersion string `json:"coder_version"`
@ -60,7 +61,7 @@ type ReportOptions struct {
type defaultChecker struct{}
func (defaultChecker) DERP(ctx context.Context, opts *DERPReportOptions) (report DERPReport) {
func (defaultChecker) DERP(ctx context.Context, opts *derphealth.ReportOptions) (report derphealth.Report) {
report.Run(ctx, opts)
return report
}
@ -99,7 +100,7 @@ func Run(ctx context.Context, opts *ReportOptions) *Report {
}
}()
report.DERP = opts.Checker.DERP(ctx, &DERPReportOptions{
report.DERP = opts.Checker.DERP(ctx, &derphealth.ReportOptions{
DERPMap: opts.DERPMap,
})
}()

View File

@ -7,16 +7,17 @@ import (
"github.com/stretchr/testify/assert"
"github.com/coder/coder/v2/coderd/healthcheck"
"github.com/coder/coder/v2/coderd/healthcheck/derphealth"
)
type testChecker struct {
DERPReport healthcheck.DERPReport
DERPReport derphealth.Report
AccessURLReport healthcheck.AccessURLReport
WebsocketReport healthcheck.WebsocketReport
DatabaseReport healthcheck.DatabaseReport
}
func (c *testChecker) DERP(context.Context, *healthcheck.DERPReportOptions) healthcheck.DERPReport {
func (c *testChecker) DERP(context.Context, *derphealth.ReportOptions) derphealth.Report {
return c.DERPReport
}
@ -43,7 +44,7 @@ func TestHealthcheck(t *testing.T) {
}{{
name: "OK",
checker: &testChecker{
DERPReport: healthcheck.DERPReport{
DERPReport: derphealth.Report{
Healthy: true,
},
AccessURLReport: healthcheck.AccessURLReport{
@ -61,7 +62,7 @@ func TestHealthcheck(t *testing.T) {
}, {
name: "DERPFail",
checker: &testChecker{
DERPReport: healthcheck.DERPReport{
DERPReport: derphealth.Report{
Healthy: false,
},
AccessURLReport: healthcheck.AccessURLReport{
@ -79,7 +80,7 @@ func TestHealthcheck(t *testing.T) {
}, {
name: "AccessURLFail",
checker: &testChecker{
DERPReport: healthcheck.DERPReport{
DERPReport: derphealth.Report{
Healthy: true,
},
AccessURLReport: healthcheck.AccessURLReport{
@ -97,7 +98,7 @@ func TestHealthcheck(t *testing.T) {
}, {
name: "WebsocketFail",
checker: &testChecker{
DERPReport: healthcheck.DERPReport{
DERPReport: derphealth.Report{
Healthy: true,
},
AccessURLReport: healthcheck.AccessURLReport{
@ -115,7 +116,7 @@ func TestHealthcheck(t *testing.T) {
}, {
name: "DatabaseFail",
checker: &testChecker{
DERPReport: healthcheck.DERPReport{
DERPReport: derphealth.Report{
Healthy: true,
},
AccessURLReport: healthcheck.AccessURLReport{