Skip to content

Commit ba174ad

Browse files
committed
only check provisioner major api version mismatch
1 parent b5e5ef0 commit ba174ad

File tree

3 files changed

+88
-85
lines changed

3 files changed

+88
-85
lines changed

coderd/healthcheck/health/model.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ const (
3535
CodeDERPNodeUsesWebsocket Code = `EDERP01`
3636
CodeDERPOneNodeUnhealthy Code = `EDERP02`
3737

38-
CodeProvisionerDaemonsNoProvisionerDaemons Code = `EPD01`
39-
CodeProvisionerDaemonVersionMismatch Code = `EPD02`
40-
CodeProvisionerDaemonAPIVersionIncompatible Code = `EPD03`
38+
CodeProvisionerDaemonsNoProvisionerDaemons Code = `EPD01`
39+
CodeProvisionerDaemonVersionMismatch Code = `EPD02`
40+
CodeProvisionerDaemonAPIMajorVersionDeprecated Code = `EPD03`
4141
)
4242

4343
// @typescript-generate Severity

coderd/healthcheck/provisioner.go

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/coder/coder/v2/coderd/util/apiversion"
1515
"github.com/coder/coder/v2/coderd/util/ptr"
1616
"github.com/coder/coder/v2/codersdk"
17+
"github.com/coder/coder/v2/provisionersdk"
1718
)
1819

1920
// @typescript-generate ProvisionerDaemonsReport
@@ -27,8 +28,8 @@ type ProvisionerDaemonsReport struct {
2728
}
2829

2930
type ProvisionerDaemonsReportOptions struct {
30-
CurrentVersion string
31-
CurrentAPIVersion *apiversion.APIVersion
31+
CurrentVersion string
32+
CurrentAPIMajorVersion int
3233

3334
// ProvisionerDaemonsFn is a function that returns ProvisionerDaemons.
3435
// Satisfied by database.Store.ProvisionerDaemons
@@ -56,9 +57,9 @@ func (r *ProvisionerDaemonsReport) Run(ctx context.Context, opts *ProvisionerDae
5657
return
5758
}
5859

59-
if opts.CurrentAPIVersion == nil {
60+
if opts.CurrentAPIMajorVersion == 0 {
6061
r.Severity = health.SeverityError
61-
r.Error = ptr.Ref("Developer error: CurrentAPIVersion is nil!")
62+
r.Error = ptr.Ref("Developer error: CurrentAPIVersion must be non-zero!")
6263
return
6364
}
6465

@@ -97,8 +98,8 @@ func (r *ProvisionerDaemonsReport) Run(ctx context.Context, opts *ProvisionerDae
9798
}
9899
// For release versions, just check MAJOR.MINOR and ignore patch.
99100
if !semver.IsValid(daemon.Version) {
100-
if r.Severity.Value() < health.SeverityWarning.Value() {
101-
r.Severity = health.SeverityWarning
101+
if r.Severity.Value() < health.SeverityError.Value() {
102+
r.Severity = health.SeverityError
102103
}
103104
r.Warnings = append(r.Warnings, health.Messagef(health.CodeUnknown, "Provisioner daemon %q reports invalid version %q", opts.CurrentVersion, daemon.Version))
104105
} else if !buildinfo.VersionsMatch(opts.CurrentVersion, daemon.Version) {
@@ -108,17 +109,20 @@ func (r *ProvisionerDaemonsReport) Run(ctx context.Context, opts *ProvisionerDae
108109
r.Warnings = append(r.Warnings, health.Messagef(health.CodeProvisionerDaemonVersionMismatch, "Provisioner daemon %q has outdated version %q", daemon.Name, daemon.Version))
109110
}
110111

111-
// Provisioner daemon API version follows different rules.
112-
if _, _, err := apiversion.Parse(daemon.APIVersion); err != nil {
112+
// Provisioner daemon API version follows different rules; we just want to check the major API version and
113+
// warn about potential later deprecations.
114+
// When we check API versions of connecting provisioner daemons, all active provisioner daemons
115+
// will, by neccessity, have a compatible API version.
116+
if maj, _, err := apiversion.Parse(daemon.APIVersion); err != nil {
113117
if r.Severity.Value() < health.SeverityError.Value() {
114118
r.Severity = health.SeverityError
115119
}
116120
r.Warnings = append(r.Warnings, health.Messagef(health.CodeUnknown, "Provisioner daemon %q reports invalid API version: %s", daemon.Name, err.Error()))
117-
} else if err := opts.CurrentAPIVersion.Validate(daemon.APIVersion); err != nil {
118-
if r.Severity.Value() < health.SeverityError.Value() {
119-
r.Severity = health.SeverityError
121+
} else if maj != opts.CurrentAPIMajorVersion {
122+
if r.Severity.Value() < health.SeverityWarning.Value() {
123+
r.Severity = health.SeverityWarning
120124
}
121-
r.Warnings = append(r.Warnings, health.Messagef(health.CodeProvisionerDaemonAPIVersionIncompatible, "Provisioner daemon %q reports incompatible API version: %s", daemon.Name, err.Error()))
125+
r.Warnings = append(r.Warnings, health.Messagef(health.CodeProvisionerDaemonAPIMajorVersionDeprecated, "Provisioner daemon %q reports deprecated major API version %d. Consider upgrading!", daemon.Name, provisionersdk.CurrentMajor))
122126
}
123127
}
124128
}

coderd/healthcheck/provisioner_test.go

Lines changed: 69 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,20 @@ import (
1313
"github.com/coder/coder/v2/coderd/database/dbtime"
1414
"github.com/coder/coder/v2/coderd/healthcheck"
1515
"github.com/coder/coder/v2/coderd/healthcheck/health"
16-
"github.com/coder/coder/v2/coderd/util/apiversion"
1716
"github.com/coder/coder/v2/provisionersdk"
1817
)
1918

2019
func TestProvisionerDaemonReport(t *testing.T) {
2120
t.Parallel()
2221

2322
for _, tt := range []struct {
24-
name string
25-
currentVersion string
26-
currentAPIVersion *apiversion.APIVersion
27-
provisionerDaemonsFn func(context.Context) ([]database.ProvisionerDaemon, error)
28-
expectedSeverity health.Severity
29-
expectedWarningCode health.Code
30-
expectedError string
23+
name string
24+
currentVersion string
25+
currentAPIMajorVersion int
26+
provisionerDaemonsFn func(context.Context) ([]database.ProvisionerDaemon, error)
27+
expectedSeverity health.Severity
28+
expectedWarningCode health.Code
29+
expectedError string
3130
}{
3231
{
3332
name: "current version empty",
@@ -36,92 +35,93 @@ func TestProvisionerDaemonReport(t *testing.T) {
3635
expectedError: "Developer error: CurrentVersion is empty",
3736
},
3837
{
39-
name: "provisionerdaemonsfn nil",
40-
currentVersion: "v1.2.3",
41-
currentAPIVersion: provisionersdk.VersionCurrent,
42-
expectedSeverity: health.SeverityError,
43-
expectedError: "Developer error: ProvisionerDaemonsFn is nil",
38+
name: "provisionerdaemonsfn nil",
39+
currentVersion: "v1.2.3",
40+
currentAPIMajorVersion: 1,
41+
expectedSeverity: health.SeverityError,
42+
expectedError: "Developer error: ProvisionerDaemonsFn is nil",
4443
},
4544
{
46-
name: "no daemons",
47-
currentVersion: "v1.2.3",
48-
currentAPIVersion: provisionersdk.VersionCurrent,
49-
provisionerDaemonsFn: fakeProvisionerDaemonsFn(),
50-
expectedSeverity: health.SeverityError,
51-
expectedError: "No provisioner daemons found!",
45+
name: "no daemons",
46+
currentVersion: "v1.2.3",
47+
currentAPIMajorVersion: provisionersdk.CurrentMajor,
48+
provisionerDaemonsFn: fakeProvisionerDaemonsFn(),
49+
expectedSeverity: health.SeverityError,
50+
expectedError: "No provisioner daemons found!",
5251
},
5352
{
54-
name: "error fetching daemons",
55-
currentVersion: "v1.2.3",
56-
currentAPIVersion: provisionersdk.VersionCurrent,
57-
provisionerDaemonsFn: fakeProvisionerDaemonsFnErr(assert.AnError),
58-
expectedSeverity: health.SeverityError,
59-
expectedError: assert.AnError.Error(),
53+
name: "error fetching daemons",
54+
currentVersion: "v1.2.3",
55+
currentAPIMajorVersion: provisionersdk.CurrentMajor,
56+
provisionerDaemonsFn: fakeProvisionerDaemonsFnErr(assert.AnError),
57+
expectedSeverity: health.SeverityError,
58+
expectedError: assert.AnError.Error(),
6059
},
6160
{
62-
name: "one daemon up to date",
63-
currentVersion: "v1.2.3",
64-
currentAPIVersion: provisionersdk.VersionCurrent,
65-
expectedSeverity: health.SeverityOK,
66-
provisionerDaemonsFn: fakeProvisionerDaemonsFn(fakeProvisionerDaemon(t, "pd-ok", "v1.2.3", "1.0")),
61+
name: "one daemon up to date",
62+
currentVersion: "v1.2.3",
63+
currentAPIMajorVersion: provisionersdk.CurrentMajor,
64+
expectedSeverity: health.SeverityOK,
65+
provisionerDaemonsFn: fakeProvisionerDaemonsFn(fakeProvisionerDaemon(t, "pd-ok", "v1.2.3", "1.0")),
6766
},
6867
{
69-
name: "one daemon out of date",
70-
currentVersion: "v1.2.3",
71-
currentAPIVersion: provisionersdk.VersionCurrent,
72-
expectedSeverity: health.SeverityWarning,
73-
expectedWarningCode: health.CodeProvisionerDaemonVersionMismatch,
74-
provisionerDaemonsFn: fakeProvisionerDaemonsFn(fakeProvisionerDaemon(t, "pd-old", "v1.1.2", "1.0")),
68+
name: "one daemon out of date",
69+
currentVersion: "v1.2.3",
70+
currentAPIMajorVersion: provisionersdk.CurrentMajor,
71+
expectedSeverity: health.SeverityWarning,
72+
expectedWarningCode: health.CodeProvisionerDaemonVersionMismatch,
73+
provisionerDaemonsFn: fakeProvisionerDaemonsFn(fakeProvisionerDaemon(t, "pd-old", "v1.1.2", "1.0")),
7574
},
7675
{
77-
name: "major api version not available",
78-
currentVersion: "v1.2.3",
79-
currentAPIVersion: provisionersdk.VersionCurrent,
80-
expectedSeverity: health.SeverityError,
81-
expectedWarningCode: health.CodeProvisionerDaemonAPIVersionIncompatible,
82-
provisionerDaemonsFn: fakeProvisionerDaemonsFn(fakeProvisionerDaemon(t, "pd-new-major", "v1.2.3", "2.0")),
76+
name: "invalid daemon version",
77+
currentVersion: "v1.2.3",
78+
currentAPIMajorVersion: provisionersdk.CurrentMajor,
79+
expectedSeverity: health.SeverityError,
80+
expectedWarningCode: health.CodeUnknown,
81+
provisionerDaemonsFn: fakeProvisionerDaemonsFn(fakeProvisionerDaemon(t, "pd-invalid-version", "invalid", "1.0")),
8382
},
8483
{
85-
name: "minor api version not available",
86-
currentVersion: "v1.2.3",
87-
currentAPIVersion: provisionersdk.VersionCurrent,
88-
expectedSeverity: health.SeverityError,
89-
expectedWarningCode: health.CodeProvisionerDaemonAPIVersionIncompatible,
90-
provisionerDaemonsFn: fakeProvisionerDaemonsFn(fakeProvisionerDaemon(t, "pd-new-minor", "v1.2.3", "1.1")),
84+
name: "invalid daemon api version",
85+
currentVersion: "v1.2.3",
86+
currentAPIMajorVersion: provisionersdk.CurrentMajor,
87+
expectedSeverity: health.SeverityError,
88+
expectedWarningCode: health.CodeUnknown,
89+
provisionerDaemonsFn: fakeProvisionerDaemonsFn(fakeProvisionerDaemon(t, "pd-new-minor", "v1.2.3", "invalid")),
9190
},
9291
{
93-
name: "api version backward compat",
94-
currentVersion: "v2.3.4",
95-
currentAPIVersion: apiversion.New(2, 0).WithBackwardCompat(1),
96-
expectedSeverity: health.SeverityOK,
92+
name: "api version backward compat",
93+
currentVersion: "v2.3.4",
94+
currentAPIMajorVersion: 2,
95+
expectedSeverity: health.SeverityWarning,
96+
expectedWarningCode: health.CodeProvisionerDaemonAPIMajorVersionDeprecated,
9797
provisionerDaemonsFn: fakeProvisionerDaemonsFn(
9898
fakeProvisionerDaemon(t, "pd-old-api", "v2.3.4", "1.0")),
9999
},
100100
{
101-
name: "one up to date, one out of date",
102-
currentVersion: "v1.2.3",
103-
currentAPIVersion: provisionersdk.VersionCurrent,
104-
expectedSeverity: health.SeverityWarning,
105-
expectedWarningCode: health.CodeProvisionerDaemonVersionMismatch,
101+
name: "one up to date, one out of date",
102+
currentVersion: "v1.2.3",
103+
currentAPIMajorVersion: provisionersdk.CurrentMajor,
104+
expectedSeverity: health.SeverityWarning,
105+
expectedWarningCode: health.CodeProvisionerDaemonVersionMismatch,
106106
provisionerDaemonsFn: fakeProvisionerDaemonsFn(
107107
fakeProvisionerDaemon(t, "pd-ok", "v1.2.3", "1.0"),
108108
fakeProvisionerDaemon(t, "pd-old", "v1.1.2", "1.0")),
109109
},
110110
{
111-
name: "one up to date, one newer",
112-
currentVersion: "v1.2.3",
113-
currentAPIVersion: provisionersdk.VersionCurrent,
114-
expectedSeverity: health.SeverityWarning,
115-
expectedWarningCode: health.CodeProvisionerDaemonVersionMismatch,
111+
name: "one up to date, one newer",
112+
currentVersion: "v1.2.3",
113+
currentAPIMajorVersion: provisionersdk.CurrentMajor,
114+
expectedSeverity: health.SeverityWarning,
115+
expectedWarningCode: health.CodeProvisionerDaemonVersionMismatch,
116116
provisionerDaemonsFn: fakeProvisionerDaemonsFn(
117117
fakeProvisionerDaemon(t, "pd-ok", "v1.2.3", "1.0"),
118118
fakeProvisionerDaemon(t, "pd-new", "v2.3.4", "1.0")),
119119
},
120120
{
121-
name: "one up to date, one stale older",
122-
currentVersion: "v2.3.4",
123-
currentAPIVersion: provisionersdk.VersionCurrent,
124-
expectedSeverity: health.SeverityOK,
121+
name: "one up to date, one stale older",
122+
currentVersion: "v2.3.4",
123+
currentAPIMajorVersion: provisionersdk.CurrentMajor,
124+
expectedSeverity: health.SeverityOK,
125125
provisionerDaemonsFn: fakeProvisionerDaemonsFn(
126126
fakeProvisionerDaemonStale(t, "pd-ok", "v1.2.3", "0.9", dbtime.Now().Add(-5*time.Minute)),
127127
fakeProvisionerDaemon(t, "pd-new", "v2.3.4", "1.0")),
@@ -134,10 +134,9 @@ func TestProvisionerDaemonReport(t *testing.T) {
134134
var rpt healthcheck.ProvisionerDaemonsReport
135135
var opts healthcheck.ProvisionerDaemonsReportOptions
136136
opts.CurrentVersion = tt.currentVersion
137-
if tt.currentAPIVersion == nil {
138-
opts.CurrentAPIVersion = provisionersdk.VersionCurrent
139-
} else {
140-
opts.CurrentAPIVersion = tt.currentAPIVersion
137+
opts.CurrentAPIMajorVersion = tt.currentAPIMajorVersion
138+
if tt.currentAPIMajorVersion == 0 {
139+
opts.CurrentAPIMajorVersion = provisionersdk.CurrentMajor
141140
}
142141
if tt.provisionerDaemonsFn != nil {
143142
opts.ProvisionerDaemonsFn = tt.provisionerDaemonsFn

0 commit comments

Comments
 (0)