mirror of
https://github.com/coder/coder.git
synced 2026-09-22 05:05:20 +08:00
fix: allow coderd to start with an empty DERP map when built-in DERP is disabled (#24544)
Allow coderd to start with an empty base DERP map when built-in DERP is disabled and no static DERP map is configured, so DERP can come from workspace proxies after startup. Also add a DERP healthcheck warning when no DERP servers are currently available at runtime. Related to: https://linear.app/codercom/issue/PLAT-43/bug-coderd-unable-to-be-started-if-built-in-derp-server-disabled-and Related to: https://github.com/coder/coder/issues/22324
This commit is contained in:
Generated
+2
@@ -23736,6 +23736,7 @@ const docTemplate = `{
|
||||
"EACS04",
|
||||
"EDERP01",
|
||||
"EDERP02",
|
||||
"EDERP03",
|
||||
"EPD01",
|
||||
"EPD02",
|
||||
"EPD03"
|
||||
@@ -23756,6 +23757,7 @@ const docTemplate = `{
|
||||
"CodeAccessURLNotOK",
|
||||
"CodeDERPNodeUsesWebsocket",
|
||||
"CodeDERPOneNodeUnhealthy",
|
||||
"CodeDERPNoNodes",
|
||||
"CodeProvisionerDaemonsNoProvisionerDaemons",
|
||||
"CodeProvisionerDaemonVersionMismatch",
|
||||
"CodeProvisionerDaemonAPIMajorVersionDeprecated"
|
||||
|
||||
Generated
+2
@@ -21863,6 +21863,7 @@
|
||||
"EACS04",
|
||||
"EDERP01",
|
||||
"EDERP02",
|
||||
"EDERP03",
|
||||
"EPD01",
|
||||
"EPD02",
|
||||
"EPD03"
|
||||
@@ -21883,6 +21884,7 @@
|
||||
"CodeAccessURLNotOK",
|
||||
"CodeDERPNodeUsesWebsocket",
|
||||
"CodeDERPOneNodeUnhealthy",
|
||||
"CodeDERPNoNodes",
|
||||
"CodeProvisionerDaemonsNoProvisionerDaemons",
|
||||
"CodeProvisionerDaemonVersionMismatch",
|
||||
"CodeProvisionerDaemonAPIMajorVersionDeprecated"
|
||||
|
||||
@@ -560,12 +560,19 @@ func NewOptions(t testing.TB, options *Options) (func(http.Handler), context.Can
|
||||
if !options.DeploymentValues.DERP.Server.Enable.Value() {
|
||||
region = nil
|
||||
}
|
||||
derpMap, err := tailnet.NewDERPMap(ctx, region, stunAddresses,
|
||||
options.DeploymentValues.DERP.Config.URL.Value(),
|
||||
options.DeploymentValues.DERP.Config.Path.Value(),
|
||||
options.DeploymentValues.DERP.Config.BlockDirect.Value(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
derpConfigURL := options.DeploymentValues.DERP.Config.URL.Value()
|
||||
derpConfigPath := options.DeploymentValues.DERP.Config.Path.Value()
|
||||
var derpMap *tailcfg.DERPMap
|
||||
if region == nil && derpConfigURL == "" && derpConfigPath == "" {
|
||||
derpMap = &tailcfg.DERPMap{Regions: map[int]*tailcfg.DERPRegion{}}
|
||||
} else {
|
||||
derpMap, err = tailnet.NewDERPMap(
|
||||
ctx, region, stunAddresses,
|
||||
derpConfigURL, derpConfigPath,
|
||||
options.DeploymentValues.DERP.Config.BlockDirect.Value(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
return func(h http.Handler) {
|
||||
mutex.Lock()
|
||||
|
||||
@@ -34,6 +34,7 @@ const (
|
||||
oneNodeUnhealthy = "Region is operational, but performance might be degraded as one node is unhealthy."
|
||||
missingNodeReport = "Missing node health report, probably a developer error."
|
||||
noSTUN = "No STUN servers are available."
|
||||
noDERP = "No DERP servers are available."
|
||||
stunMapVaryDest = "STUN returned different addresses; you may be behind a hard NAT."
|
||||
)
|
||||
|
||||
@@ -69,11 +70,20 @@ func (r *Report) Run(ctx context.Context, opts *ReportOptions) {
|
||||
|
||||
r.Regions = map[int]*healthsdk.DERPRegionReport{}
|
||||
|
||||
// Track whether the map contains any DERP nodes so we can warn if
|
||||
// it does not.
|
||||
hasDERP := false
|
||||
wg := &sync.WaitGroup{}
|
||||
mu := sync.Mutex{}
|
||||
|
||||
wg.Add(len(opts.DERPMap.Regions))
|
||||
for _, region := range opts.DERPMap.Regions {
|
||||
for _, node := range region.Nodes {
|
||||
if !node.STUNOnly {
|
||||
hasDERP = true
|
||||
break
|
||||
}
|
||||
}
|
||||
var (
|
||||
region = region
|
||||
regionReport = RegionReport{
|
||||
@@ -103,6 +113,12 @@ func (r *Report) Run(ctx context.Context, opts *ReportOptions) {
|
||||
mu.Unlock()
|
||||
}()
|
||||
}
|
||||
if !hasDERP {
|
||||
r.Severity = health.SeverityWarning
|
||||
r.Warnings = append(r.Warnings, health.Messagef(
|
||||
health.CodeDERPNoNodes, noDERP,
|
||||
))
|
||||
}
|
||||
|
||||
ncLogf := func(format string, args ...interface{}) {
|
||||
mu.Lock()
|
||||
|
||||
@@ -64,6 +64,9 @@ func TestDERP(t *testing.T) {
|
||||
report.Run(ctx, opts)
|
||||
|
||||
assert.True(t, report.Healthy)
|
||||
for _, warning := range report.Warnings {
|
||||
assert.NotEqual(t, health.CodeDERPNoNodes, warning.Code)
|
||||
}
|
||||
for _, region := range report.Regions {
|
||||
assert.True(t, region.Healthy)
|
||||
for _, node := range region.NodeReports {
|
||||
@@ -361,7 +364,7 @@ func TestDERP(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("STUNOnly/OK", func(t *testing.T) {
|
||||
t.Run("STUNOnly/WarnsNoDERP", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var (
|
||||
@@ -389,7 +392,9 @@ func TestDERP(t *testing.T) {
|
||||
report.Run(ctx, opts)
|
||||
|
||||
assert.True(t, report.Healthy)
|
||||
assert.Equal(t, health.SeverityOK, report.Severity)
|
||||
assert.Equal(t, health.SeverityWarning, report.Severity)
|
||||
require.Len(t, report.Warnings, 1)
|
||||
assert.Equal(t, health.CodeDERPNoNodes, report.Warnings[0].Code)
|
||||
for _, region := range report.Regions {
|
||||
assert.True(t, region.Healthy)
|
||||
assert.Equal(t, health.SeverityOK, region.Severity)
|
||||
@@ -405,6 +410,27 @@ func TestDERP(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("NoDERP/EmptyMap", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var (
|
||||
ctx = context.Background()
|
||||
report = derphealth.Report{}
|
||||
opts = &derphealth.ReportOptions{
|
||||
DERPMap: &tailcfg.DERPMap{
|
||||
Regions: map[int]*tailcfg.DERPRegion{},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
report.Run(ctx, opts)
|
||||
|
||||
assert.Equal(t, health.SeverityWarning, report.Severity)
|
||||
require.Len(t, report.Warnings, 1)
|
||||
assert.Equal(t, health.CodeDERPNoNodes, report.Warnings[0].Code)
|
||||
assert.Empty(t, report.Regions)
|
||||
})
|
||||
|
||||
t.Run("STUNOnly/OneBadOneGood", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -443,9 +469,15 @@ func TestDERP(t *testing.T) {
|
||||
report.Run(ctx, opts)
|
||||
assert.True(t, report.Healthy)
|
||||
assert.Equal(t, health.SeverityWarning, report.Severity)
|
||||
if assert.Len(t, report.Warnings, 1) {
|
||||
assert.Equal(t, health.CodeDERPOneNodeUnhealthy, report.Warnings[0].Code)
|
||||
}
|
||||
assert.Len(t, report.Warnings, 2)
|
||||
assert.Contains(t, []health.Code{
|
||||
report.Warnings[0].Code,
|
||||
report.Warnings[1].Code,
|
||||
}, health.CodeDERPOneNodeUnhealthy)
|
||||
assert.Contains(t, []health.Code{
|
||||
report.Warnings[0].Code,
|
||||
report.Warnings[1].Code,
|
||||
}, health.CodeDERPNoNodes)
|
||||
for _, region := range report.Regions {
|
||||
assert.True(t, region.Healthy)
|
||||
assert.Equal(t, health.SeverityWarning, region.Severity)
|
||||
|
||||
@@ -36,6 +36,7 @@ const (
|
||||
|
||||
CodeDERPNodeUsesWebsocket Code = `EDERP01`
|
||||
CodeDERPOneNodeUnhealthy Code = `EDERP02`
|
||||
CodeDERPNoNodes Code = `EDERP03`
|
||||
CodeSTUNNoNodes = `ESTUN01`
|
||||
CodeSTUNMapVaryDest = `ESTUN02`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user