Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit6beb53d

Browse files
committed
feat: Add support for checking for updates
1 parent898ba11 commit6beb53d

File tree

17 files changed

+664
-12
lines changed

17 files changed

+664
-12
lines changed

‎buildinfo/buildinfo.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ func VersionsMatch(v1, v2 string) bool {
6868
returnsemver.MajorMinor(v1)==semver.MajorMinor(v2)
6969
}
7070

71+
// IsDev returns true if this is a development build.
72+
funcIsDev()bool {
73+
returnstrings.HasPrefix(Version(),develPrefix)
74+
}
75+
7176
// ExternalURL returns a URL referencing the current Coder version.
7277
// For production builds, this will link directly to a release.
7378
// For development builds, this will link to a commit.

‎cli/deployment/config.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/spf13/viper"
1515
"golang.org/x/xerrors"
1616

17+
"github.com/coder/coder/buildinfo"
1718
"github.com/coder/coder/cli/cliui"
1819
"github.com/coder/coder/cli/config"
1920
"github.com/coder/coder/codersdk"
@@ -405,6 +406,12 @@ func newConfig() *codersdk.DeploymentConfig {
405406
Usage:"Enable experimental features. Experimental features are not ready for production.",
406407
Flag:"experimental",
407408
},
409+
UpdateCheck:&codersdk.DeploymentConfigField[bool]{
410+
Name:"Update Check",
411+
Usage:"Periodically check for new releases of Coder and inform the owner.",
412+
Flag:"update-check",
413+
Default:flag.Lookup("test.v")==nil&&!buildinfo.IsDev(),
414+
},
408415
}
409416
}
410417

‎cli/deployment/config_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ func TestConfig(t *testing.T) {
3838
"CODER_TELEMETRY":"false",
3939
"CODER_TELEMETRY_TRACE":"false",
4040
"CODER_WILDCARD_ACCESS_URL":"something-wildcard.com",
41+
"CODER_UPDATE_CHECK":"false",
4142
},
4243
Valid:func(config*codersdk.DeploymentConfig) {
4344
require.Equal(t,config.Address.Value,"0.0.0.0:8443")
@@ -53,6 +54,7 @@ func TestConfig(t *testing.T) {
5354
require.Equal(t,config.Telemetry.Enable.Value,false)
5455
require.Equal(t,config.Telemetry.Trace.Value,false)
5556
require.Equal(t,config.WildcardAccessURL.Value,"something-wildcard.com")
57+
require.Equal(t,config.UpdateCheck.Value,false)
5658
},
5759
}, {
5860
Name:"DERP",

‎cli/server.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ import (
6363
"github.com/coder/coder/coderd/prometheusmetrics"
6464
"github.com/coder/coder/coderd/telemetry"
6565
"github.com/coder/coder/coderd/tracing"
66+
"github.com/coder/coder/coderd/updatecheck"
6667
"github.com/coder/coder/codersdk"
6768
"github.com/coder/coder/cryptorand"
6869
"github.com/coder/coder/provisioner/echo"
@@ -370,6 +371,25 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
370371
options.TLSCertificates=tlsConfig.Certificates
371372
}
372373

374+
ifcfg.UpdateCheck.Value {
375+
options.UpdateCheckOptions=&updatecheck.Options{
376+
// Avoid spamming GitHub API checking for updates.
377+
Interval:24*time.Hour,
378+
// Inform server admins of new versions.
379+
Notify:func(r updatecheck.Result) {
380+
ifsemver.Compare(r.Version,buildinfo.Version())>0 {
381+
options.Logger.Info(
382+
context.Background(),
383+
"new version of coder available",
384+
slog.F("new_version",r.Version),
385+
slog.F("url",r.URL),
386+
slog.F("upgrade_instructions","https://coder.com/docs/coder-oss/latest/admin/upgrade"),
387+
)
388+
}
389+
},
390+
}
391+
}
392+
373393
ifcfg.OAuth2.Github.ClientSecret.Value!="" {
374394
options.GithubOAuth2Config,err=configureGithubOAuth2(accessURLParsed,
375395
cfg.OAuth2.Github.ClientID.Value,

‎coderd/coderd.go

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import (
4747
"github.com/coder/coder/coderd/rbac"
4848
"github.com/coder/coder/coderd/telemetry"
4949
"github.com/coder/coder/coderd/tracing"
50+
"github.com/coder/coder/coderd/updatecheck"
5051
"github.com/coder/coder/coderd/wsconncache"
5152
"github.com/coder/coder/codersdk"
5253
"github.com/coder/coder/provisionerd/proto"
@@ -105,6 +106,7 @@ type Options struct {
105106
AgentStatsRefreshInterval time.Duration
106107
Experimentalbool
107108
DeploymentConfig*codersdk.DeploymentConfig
109+
UpdateCheckOptions*updatecheck.Options// Set non-nil to enable update checking.
108110
}
109111

110112
// New constructs a Coder API handler.
@@ -123,20 +125,14 @@ func New(options *Options) *API {
123125
options.AgentInactiveDisconnectTimeout=options.AgentConnectionUpdateFrequency*2
124126
}
125127
ifoptions.AgentStatsRefreshInterval==0 {
126-
options.AgentStatsRefreshInterval=10*time.Minute
128+
options.AgentStatsRefreshInterval=5*time.Minute
127129
}
128130
ifoptions.MetricsCacheRefreshInterval==0 {
129131
options.MetricsCacheRefreshInterval=time.Hour
130132
}
131133
ifoptions.APIRateLimit==0 {
132134
options.APIRateLimit=512
133135
}
134-
ifoptions.AgentStatsRefreshInterval==0 {
135-
options.AgentStatsRefreshInterval=5*time.Minute
136-
}
137-
ifoptions.MetricsCacheRefreshInterval==0 {
138-
options.MetricsCacheRefreshInterval=time.Hour
139-
}
140136
ifoptions.Authorizer==nil {
141137
options.Authorizer=rbac.NewAuthorizer()
142138
}
@@ -181,6 +177,13 @@ func New(options *Options) *API {
181177
metricsCache:metricsCache,
182178
Auditor: atomic.Pointer[audit.Auditor]{},
183179
}
180+
ifoptions.UpdateCheckOptions!=nil {
181+
api.updateChecker=updatecheck.New(
182+
options.Database,
183+
options.Logger.Named("update_checker"),
184+
*options.UpdateCheckOptions,
185+
)
186+
}
184187
api.Auditor.Store(&options.Auditor)
185188
api.workspaceAgentCache=wsconncache.New(api.dialWorkspaceAgentTailnet,0)
186189
api.TailnetCoordinator.Store(&options.TailnetCoordinator)
@@ -308,6 +311,9 @@ func New(options *Options) *API {
308311
})
309312
})
310313
})
314+
r.Route("/updatecheck",func(r chi.Router) {
315+
r.Get("/",api.updateCheck)
316+
})
311317
r.Route("/config",func(r chi.Router) {
312318
r.Use(apiKeyMiddleware)
313319
r.Get("/deployment",api.deploymentConfig)
@@ -598,13 +604,14 @@ type API struct {
598604
// RootHandler serves "/"
599605
RootHandler chi.Router
600606

601-
metricsCache*metricscache.Cache
602-
siteHandler http.Handler
607+
siteHandler http.Handler
603608

604609
WebsocketWaitMutex sync.Mutex
605610
WebsocketWaitGroup sync.WaitGroup
606611

612+
metricsCache*metricscache.Cache
607613
workspaceAgentCache*wsconncache.Cache
614+
updateChecker*updatecheck.Checker
608615
}
609616

610617
// Close waits for all WebSocket connections to drain before returning.
@@ -614,6 +621,9 @@ func (api *API) Close() error {
614621
api.WebsocketWaitMutex.Unlock()
615622

616623
api.metricsCache.Close()
624+
ifapi.updateChecker!=nil {
625+
api.updateChecker.Close()
626+
}
617627
coordinator:=api.TailnetCoordinator.Load()
618628
ifcoordinator!=nil {
619629
_= (*coordinator).Close()

‎coderd/coderdtest/coderdtest.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import (
6464
"github.com/coder/coder/coderd/httpmw"
6565
"github.com/coder/coder/coderd/rbac"
6666
"github.com/coder/coder/coderd/telemetry"
67+
"github.com/coder/coder/coderd/updatecheck"
6768
"github.com/coder/coder/coderd/util/ptr"
6869
"github.com/coder/coder/codersdk"
6970
"github.com/coder/coder/cryptorand"
@@ -102,6 +103,9 @@ type Options struct {
102103
AgentStatsRefreshInterval time.Duration
103104
DeploymentConfig*codersdk.DeploymentConfig
104105

106+
// Set update check options to enable update check.
107+
UpdateCheckOptions*updatecheck.Options
108+
105109
// Overriding the database is heavily discouraged.
106110
// It should only be used in cases where multiple Coder
107111
// test instances are running against the same database.
@@ -283,6 +287,7 @@ func NewOptions(t *testing.T, options *Options) (func(http.Handler), context.Can
283287
MetricsCacheRefreshInterval:options.MetricsCacheRefreshInterval,
284288
AgentStatsRefreshInterval:options.AgentStatsRefreshInterval,
285289
DeploymentConfig:options.DeploymentConfig,
290+
UpdateCheckOptions:options.UpdateCheckOptions,
286291
}
287292
}
288293

‎coderd/database/databasefake/databasefake.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,10 @@ type data struct {
112112
workspaceResources []database.WorkspaceResource
113113
workspaces []database.Workspace
114114

115-
deploymentIDstring
116-
derpMeshKeystring
117-
lastLicenseIDint32
115+
deploymentIDstring
116+
derpMeshKeystring
117+
lastUpdateCheck []byte
118+
lastLicenseIDint32
118119
}
119120

120121
func (*fakeQuerier)Ping(_ context.Context) (time.Duration,error) {
@@ -3234,6 +3235,24 @@ func (q *fakeQuerier) GetDERPMeshKey(_ context.Context) (string, error) {
32343235
returnq.derpMeshKey,nil
32353236
}
32363237

3238+
func (q*fakeQuerier)InsertOrUpdateLastUpdateCheck(_ context.Context,datastring)error {
3239+
q.mutex.RLock()
3240+
deferq.mutex.RUnlock()
3241+
3242+
q.lastUpdateCheck= []byte(data)
3243+
returnnil
3244+
}
3245+
3246+
func (q*fakeQuerier)GetLastUpdateCheck(_ context.Context) (string,error) {
3247+
q.mutex.RLock()
3248+
deferq.mutex.RUnlock()
3249+
3250+
ifq.lastUpdateCheck==nil {
3251+
return"",sql.ErrNoRows
3252+
}
3253+
returnstring(q.lastUpdateCheck),nil
3254+
}
3255+
32373256
func (q*fakeQuerier)InsertLicense(
32383257
_ context.Context,arg database.InsertLicenseParams,
32393258
) (database.License,error) {

‎coderd/database/querier.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/queries.sql.go

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/queries/siteconfig.sql

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,10 @@ INSERT INTO site_configs (key, value) VALUES ('derp_mesh_key', $1);
99

1010
-- name: GetDERPMeshKey :one
1111
SELECT valueFROM site_configsWHERE key='derp_mesh_key';
12+
13+
-- name: InsertOrUpdateLastUpdateCheck :exec
14+
INSERT INTO site_configs (key, value)VALUES ('last_update_check', $1)
15+
ON CONFLICT (key) DOUPDATESET value= $1WHEREsite_configs.key='last_update_check';
16+
17+
-- name: GetLastUpdateCheck :one
18+
SELECT valueFROM site_configsWHERE key='last_update_check';

‎coderd/updatecheck.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package coderd
2+
3+
import (
4+
"net/http"
5+
6+
"golang.org/x/mod/semver"
7+
8+
"github.com/coder/coder/buildinfo"
9+
"github.com/coder/coder/coderd/httpapi"
10+
"github.com/coder/coder/codersdk"
11+
)
12+
13+
func (api*API)updateCheck(rw http.ResponseWriter,r*http.Request) {
14+
ctx:=r.Context()
15+
16+
ifapi.updateChecker==nil {
17+
// If update checking is disabled, echo the current
18+
// version.
19+
httpapi.Write(ctx,rw,http.StatusOK, codersdk.UpdateCheckResponse{
20+
Current:true,
21+
Version:buildinfo.Version(),
22+
URL:buildinfo.ExternalURL(),
23+
})
24+
return
25+
}
26+
27+
uc,err:=api.updateChecker.Latest(ctx)
28+
iferr!=nil {
29+
httpapi.InternalServerError(rw,err)
30+
return
31+
}
32+
33+
httpapi.Write(ctx,rw,http.StatusOK, codersdk.UpdateCheckResponse{
34+
Current:semver.Compare(buildinfo.Version(),uc.Version)>=0,
35+
Version:uc.Version,
36+
URL:uc.URL,
37+
})
38+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp