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

Commit23a2811

Browse files
committed
feat: Add support for checking for updates
1 parentec4b397 commit23a2811

File tree

16 files changed

+654
-9
lines changed

16 files changed

+654
-9
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"
@@ -325,6 +326,12 @@ func newConfig() *codersdk.DeploymentConfig {
325326
Hidden:true,
326327
Default:10*time.Minute,
327328
},
329+
UpdateCheck:&codersdk.DeploymentConfigField[bool]{
330+
Name:"Update Check",
331+
Usage:"Periodically check for new releases of Coder and inform the owner.",
332+
Flag:"update-check",
333+
Default:flag.Lookup("test.v")==nil&&!buildinfo.IsDev(),
334+
},
328335
AuditLogging:&codersdk.DeploymentConfigField[bool]{
329336
Name:"Audit Logging",
330337
Usage:"Specifies whether audit logging is enabled.",

‎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
@@ -62,6 +62,7 @@ import (
6262
"github.com/coder/coder/coderd/prometheusmetrics"
6363
"github.com/coder/coder/coderd/telemetry"
6464
"github.com/coder/coder/coderd/tracing"
65+
"github.com/coder/coder/coderd/updatecheck"
6566
"github.com/coder/coder/codersdk"
6667
"github.com/coder/coder/cryptorand"
6768
"github.com/coder/coder/provisioner/echo"
@@ -363,6 +364,25 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
363364
options.TLSCertificates=tlsConfig.Certificates
364365
}
365366

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

‎coderd/coderd.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939
"github.com/coder/coder/coderd/rbac"
4040
"github.com/coder/coder/coderd/telemetry"
4141
"github.com/coder/coder/coderd/tracing"
42+
"github.com/coder/coder/coderd/updatecheck"
4243
"github.com/coder/coder/coderd/workspacequota"
4344
"github.com/coder/coder/coderd/wsconncache"
4445
"github.com/coder/coder/codersdk"
@@ -97,6 +98,7 @@ type Options struct {
9798
AgentStatsRefreshInterval time.Duration
9899
Experimentalbool
99100
DeploymentConfig*codersdk.DeploymentConfig
101+
UpdateCheckOptions*updatecheck.Options// Set non-nil to enable update checking.
100102
}
101103

102104
// New constructs a Coder API handler.
@@ -123,12 +125,6 @@ func New(options *Options) *API {
123125
ifoptions.APIRateLimit==0 {
124126
options.APIRateLimit=512
125127
}
126-
ifoptions.AgentStatsRefreshInterval==0 {
127-
options.AgentStatsRefreshInterval=10*time.Minute
128-
}
129-
ifoptions.MetricsCacheRefreshInterval==0 {
130-
options.MetricsCacheRefreshInterval=time.Hour
131-
}
132128
ifoptions.Authorizer==nil {
133129
options.Authorizer=rbac.NewAuthorizer()
134130
}
@@ -176,6 +172,13 @@ func New(options *Options) *API {
176172
Auditor: atomic.Pointer[audit.Auditor]{},
177173
WorkspaceQuotaEnforcer: atomic.Pointer[workspacequota.Enforcer]{},
178174
}
175+
ifoptions.UpdateCheckOptions!=nil {
176+
api.updateChecker=updatecheck.New(
177+
options.Database,
178+
options.Logger.Named("update_checker"),
179+
*options.UpdateCheckOptions,
180+
)
181+
}
179182
api.Auditor.Store(&options.Auditor)
180183
api.WorkspaceQuotaEnforcer.Store(&options.WorkspaceQuotaEnforcer)
181184
api.workspaceAgentCache=wsconncache.New(api.dialWorkspaceAgentTailnet,0)
@@ -302,6 +305,9 @@ func New(options *Options) *API {
302305
})
303306
})
304307
})
308+
r.Route("/updatecheck",func(r chi.Router) {
309+
r.Get("/",api.updateCheck)
310+
})
305311
r.Route("/config",func(r chi.Router) {
306312
r.Use(apiKeyMiddleware)
307313
r.Get("/deployment",api.deploymentConfig)
@@ -591,6 +597,7 @@ type API struct {
591597
RootHandler chi.Router
592598

593599
metricsCache*metricscache.Cache
600+
updateChecker*updatecheck.Checker
594601
siteHandler http.Handler
595602
websocketWaitMutex sync.Mutex
596603
websocketWaitGroup sync.WaitGroup
@@ -604,6 +611,9 @@ func (api *API) Close() error {
604611
api.websocketWaitMutex.Unlock()
605612

606613
api.metricsCache.Close()
614+
ifapi.updateChecker!=nil {
615+
api.updateChecker.Close()
616+
}
607617
coordinator:=api.TailnetCoordinator.Load()
608618
ifcoordinator!=nil {
609619
_= (*coordinator).Close()

‎coderd/coderdtest/coderdtest.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import (
6161
"github.com/coder/coder/coderd/httpmw"
6262
"github.com/coder/coder/coderd/rbac"
6363
"github.com/coder/coder/coderd/telemetry"
64+
"github.com/coder/coder/coderd/updatecheck"
6465
"github.com/coder/coder/coderd/util/ptr"
6566
"github.com/coder/coder/codersdk"
6667
"github.com/coder/coder/cryptorand"
@@ -97,6 +98,9 @@ type Options struct {
9798
AgentStatsRefreshInterval time.Duration
9899
DeploymentConfig*codersdk.DeploymentConfig
99100

101+
// Set update check options to enable update check.
102+
UpdateCheckOptions*updatecheck.Options
103+
100104
// Overriding the database is heavily discouraged.
101105
// It should only be used in cases where multiple Coder
102106
// test instances are running against the same database.
@@ -275,6 +279,7 @@ func NewOptions(t *testing.T, options *Options) (func(http.Handler), context.Can
275279
MetricsCacheRefreshInterval:options.MetricsCacheRefreshInterval,
276280
AgentStatsRefreshInterval:options.AgentStatsRefreshInterval,
277281
DeploymentConfig:options.DeploymentConfig,
282+
UpdateCheckOptions:options.UpdateCheckOptions,
278283
}
279284
}
280285

‎coderd/database/databasefake/databasefake.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,10 @@ type data struct {
111111
licenses []database.License
112112
replicas []database.Replica
113113

114-
deploymentIDstring
115-
derpMeshKeystring
116-
lastLicenseIDint32
114+
deploymentIDstring
115+
derpMeshKeystring
116+
lastUpdateCheck []byte
117+
lastLicenseIDint32
117118
}
118119

119120
func (*fakeQuerier)Ping(_ context.Context) (time.Duration,error) {
@@ -154,6 +155,7 @@ func (q *fakeQuerier) AcquireProvisionerJob(_ context.Context, arg database.Acqu
154155
}
155156
return database.ProvisionerJob{},sql.ErrNoRows
156157
}
158+
157159
func (*fakeQuerier)DeleteOldAgentStats(_ context.Context)error {
158160
// no-op
159161
returnnil
@@ -3108,6 +3110,24 @@ func (q *fakeQuerier) GetDERPMeshKey(_ context.Context) (string, error) {
31083110
returnq.derpMeshKey,nil
31093111
}
31103112

3113+
func (q*fakeQuerier)InsertOrUpdateLastUpdateCheck(_ context.Context,datastring)error {
3114+
q.mutex.RLock()
3115+
deferq.mutex.RUnlock()
3116+
3117+
q.lastUpdateCheck= []byte(data)
3118+
returnnil
3119+
}
3120+
3121+
func (q*fakeQuerier)GetLastUpdateCheck(_ context.Context) (string,error) {
3122+
q.mutex.RLock()
3123+
deferq.mutex.RUnlock()
3124+
3125+
ifq.lastUpdateCheck==nil {
3126+
return"",sql.ErrNoRows
3127+
}
3128+
returnstring(q.lastUpdateCheck),nil
3129+
}
3130+
31113131
func (q*fakeQuerier)InsertLicense(
31123132
_ context.Context,arg database.InsertLicenseParams,
31133133
) (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