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

Commit45862a7

Browse files
DanielleMaywoodaslilac
authored andcommitted
fix: update workspace TTL on template TTL change (#15761)
Relates to#15390Currently when a user creates a workspace, their workspace's TTL isdetermined by the template's default TTL. If the Coder instance is AGPL,or if the template has disallowed the user from configuring autostop,then it is not possible to change the workspace's TTL after creation.Any changes to the template's default TTL only takes effect on _new_workspaces.This PR modifies the behaviour slightly so that on AGPL Coder, or onenterprise when a template does not allow user's to configure theirworkspace's TTL, updating the template's default TTL will also updateany workspace's TTL to match this value.
1 parent1e575d8 commit45862a7

File tree

12 files changed

+518
-0
lines changed

12 files changed

+518
-0
lines changed

‎coderd/database/dbauthz/dbauthz.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4138,6 +4138,17 @@ func (q *querier) UpdateWorkspacesDormantDeletingAtByTemplateID(ctx context.Cont
41384138
returnq.db.UpdateWorkspacesDormantDeletingAtByTemplateID(ctx,arg)
41394139
}
41404140

4141+
func (q*querier)UpdateWorkspacesTTLByTemplateID(ctx context.Context,arg database.UpdateWorkspacesTTLByTemplateIDParams)error {
4142+
template,err:=q.db.GetTemplateByID(ctx,arg.TemplateID)
4143+
iferr!=nil {
4144+
returnxerrors.Errorf("get template by id: %w",err)
4145+
}
4146+
iferr:=q.authorizeContext(ctx,policy.ActionUpdate,template);err!=nil {
4147+
returnerr
4148+
}
4149+
returnq.db.UpdateWorkspacesTTLByTemplateID(ctx,arg)
4150+
}
4151+
41414152
func (q*querier)UpsertAnnouncementBanners(ctx context.Context,valuestring)error {
41424153
iferr:=q.authorizeContext(ctx,policy.ActionUpdate,rbac.ResourceDeploymentConfig);err!=nil {
41434154
returnerr

‎coderd/database/dbauthz/dbauthz_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,12 @@ func (s *MethodTestSuite) TestTemplate() {
10171017
TemplateID:t1.ID,
10181018
}).Asserts(t1,policy.ActionUpdate)
10191019
}))
1020+
s.Run("UpdateWorkspacesTTLByTemplateID",s.Subtest(func(db database.Store,check*expects) {
1021+
t1:=dbgen.Template(s.T(),db, database.Template{})
1022+
check.Args(database.UpdateWorkspacesTTLByTemplateIDParams{
1023+
TemplateID:t1.ID,
1024+
}).Asserts(t1,policy.ActionUpdate)
1025+
}))
10201026
s.Run("UpdateTemplateActiveVersionByID",s.Subtest(func(db database.Store,check*expects) {
10211027
t1:=dbgen.Template(s.T(),db, database.Template{
10221028
ActiveVersionID:uuid.New(),

‎coderd/database/dbmem/dbmem.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10192,6 +10192,26 @@ func (q *FakeQuerier) UpdateWorkspacesDormantDeletingAtByTemplateID(_ context.Co
1019210192
returnaffectedRows,nil
1019310193
}
1019410194

10195+
func (q*FakeQuerier)UpdateWorkspacesTTLByTemplateID(_ context.Context,arg database.UpdateWorkspacesTTLByTemplateIDParams)error {
10196+
err:=validateDatabaseType(arg)
10197+
iferr!=nil {
10198+
returnerr
10199+
}
10200+
10201+
q.mutex.Lock()
10202+
deferq.mutex.Unlock()
10203+
10204+
fori,ws:=rangeq.workspaces {
10205+
ifws.TemplateID!=arg.TemplateID {
10206+
continue
10207+
}
10208+
10209+
q.workspaces[i].Ttl=arg.Ttl
10210+
}
10211+
10212+
returnnil
10213+
}
10214+
1019510215
func (q*FakeQuerier)UpsertAnnouncementBanners(_ context.Context,datastring)error {
1019610216
q.mutex.RLock()
1019710217
deferq.mutex.RUnlock()

‎coderd/database/dbmetrics/querymetrics.go

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

‎coderd/database/dbmock/dbmock.go

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

‎coderd/database/querier.go

Lines changed: 1 addition & 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: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/queries/workspaces.sql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,14 @@ SET
501501
WHERE
502502
id= $1;
503503

504+
-- name: UpdateWorkspacesTTLByTemplateID :exec
505+
UPDATE
506+
workspaces
507+
SET
508+
ttl= $2
509+
WHERE
510+
template_id= $1;
511+
504512
-- name: UpdateWorkspaceLastUsedAt :exec
505513
UPDATE
506514
workspaces

‎coderd/schedule/template.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package schedule
22

33
import (
44
"context"
5+
"database/sql"
56
"time"
67

78
"github.com/google/uuid"
@@ -228,6 +229,23 @@ func (*agplTemplateScheduleStore) Set(ctx context.Context, db database.Store, tp
228229
returnxerrors.Errorf("update template schedule: %w",err)
229230
}
230231

232+
// Users running the AGPL version are unable to customize their workspaces
233+
// autostop, so we want to keep their workspaces in track with any template
234+
// TTL changes.
235+
iftpl.DefaultTTL!=int64(opts.DefaultTTL) {
236+
varttl sql.NullInt64
237+
ifopts.DefaultTTL!=0 {
238+
ttl= sql.NullInt64{Valid:true,Int64:int64(opts.DefaultTTL)}
239+
}
240+
241+
iferr=db.UpdateWorkspacesTTLByTemplateID(ctx, database.UpdateWorkspacesTTLByTemplateIDParams{
242+
TemplateID:tpl.ID,
243+
Ttl:ttl,
244+
});err!=nil {
245+
returnxerrors.Errorf("update workspace ttl by template id %q: %w",tpl.ID,err)
246+
}
247+
}
248+
231249
template,err=db.GetTemplateByID(ctx,tpl.ID)
232250
iferr!=nil {
233251
returnxerrors.Errorf("fetch updated template: %w",err)

‎coderd/schedule/template_test.go

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
package schedule_test
2+
3+
import (
4+
"database/sql"
5+
"testing"
6+
"time"
7+
8+
"github.com/stretchr/testify/require"
9+
10+
"github.com/coder/coder/v2/coderd/database"
11+
"github.com/coder/coder/v2/coderd/database/dbgen"
12+
"github.com/coder/coder/v2/coderd/database/dbtestutil"
13+
"github.com/coder/coder/v2/coderd/database/dbtime"
14+
"github.com/coder/coder/v2/coderd/schedule"
15+
"github.com/coder/coder/v2/testutil"
16+
)
17+
18+
funcTestTemplateTTL(t*testing.T) {
19+
t.Parallel()
20+
21+
tests:= []struct {
22+
namestring
23+
fromTTL time.Duration
24+
toTTL time.Duration
25+
expected sql.NullInt64
26+
}{
27+
{
28+
name:"ModifyTTLDurationDown",
29+
fromTTL:24*time.Hour,
30+
toTTL:1*time.Hour,
31+
expected: sql.NullInt64{Valid:true,Int64:int64(1*time.Hour)},
32+
},
33+
{
34+
name:"ModifyTTLDurationUp",
35+
fromTTL:24*time.Hour,
36+
toTTL:36*time.Hour,
37+
expected: sql.NullInt64{Valid:true,Int64:int64(36*time.Hour)},
38+
},
39+
{
40+
name:"ModifyTTLDurationSame",
41+
fromTTL:24*time.Hour,
42+
toTTL:24*time.Hour,
43+
expected: sql.NullInt64{Valid:true,Int64:int64(24*time.Hour)},
44+
},
45+
{
46+
name:"DisableTTL",
47+
fromTTL:24*time.Hour,
48+
toTTL:0,
49+
expected: sql.NullInt64{},
50+
},
51+
}
52+
53+
for_,tt:=rangetests {
54+
tt:=tt
55+
56+
t.Run(tt.name,func(t*testing.T) {
57+
t.Parallel()
58+
59+
var (
60+
db,_=dbtestutil.NewDB(t)
61+
ctx=testutil.Context(t,testutil.WaitLong)
62+
user=dbgen.User(t,db, database.User{})
63+
file=dbgen.File(t,db, database.File{CreatedBy:user.ID})
64+
// Create first template
65+
templateJob=dbgen.ProvisionerJob(t,db,nil, database.ProvisionerJob{
66+
FileID:file.ID,
67+
InitiatorID:user.ID,
68+
Tags: database.StringMap{"foo":"bar"},
69+
})
70+
templateVersion=dbgen.TemplateVersion(t,db, database.TemplateVersion{
71+
CreatedBy:user.ID,
72+
JobID:templateJob.ID,
73+
OrganizationID:templateJob.OrganizationID,
74+
})
75+
template=dbgen.Template(t,db, database.Template{
76+
ActiveVersionID:templateVersion.ID,
77+
CreatedBy:user.ID,
78+
OrganizationID:templateJob.OrganizationID,
79+
})
80+
// Create second template
81+
otherTTL=tt.fromTTL+6*time.Hour
82+
otherTemplateJob=dbgen.ProvisionerJob(t,db,nil, database.ProvisionerJob{
83+
FileID:file.ID,
84+
InitiatorID:user.ID,
85+
Tags: database.StringMap{"foo":"bar"},
86+
})
87+
otherTemplateVersion=dbgen.TemplateVersion(t,db, database.TemplateVersion{
88+
CreatedBy:user.ID,
89+
JobID:otherTemplateJob.ID,
90+
OrganizationID:otherTemplateJob.OrganizationID,
91+
})
92+
otherTemplate=dbgen.Template(t,db, database.Template{
93+
ActiveVersionID:otherTemplateVersion.ID,
94+
CreatedBy:user.ID,
95+
OrganizationID:otherTemplateJob.OrganizationID,
96+
})
97+
)
98+
99+
templateScheduleStore:=schedule.NewAGPLTemplateScheduleStore()
100+
101+
// Set both template's default TTL
102+
template,err:=templateScheduleStore.Set(ctx,db,template, schedule.TemplateScheduleOptions{
103+
DefaultTTL:tt.fromTTL,
104+
})
105+
require.NoError(t,err)
106+
otherTemplate,err=templateScheduleStore.Set(ctx,db,otherTemplate, schedule.TemplateScheduleOptions{
107+
DefaultTTL:otherTTL,
108+
})
109+
require.NoError(t,err)
110+
111+
// We create two workspaces here, one with the template we're modifying, the
112+
// other with a different template. We want to ensure we only modify one
113+
// of the workspaces.
114+
workspace:=dbgen.Workspace(t,db, database.WorkspaceTable{
115+
OwnerID:user.ID,
116+
TemplateID:template.ID,
117+
OrganizationID:templateJob.OrganizationID,
118+
LastUsedAt:dbtime.Now(),
119+
Ttl: sql.NullInt64{Valid:true,Int64:int64(tt.fromTTL)},
120+
})
121+
otherWorkspace:=dbgen.Workspace(t,db, database.WorkspaceTable{
122+
OwnerID:user.ID,
123+
TemplateID:otherTemplate.ID,
124+
OrganizationID:otherTemplateJob.OrganizationID,
125+
LastUsedAt:dbtime.Now(),
126+
Ttl: sql.NullInt64{Valid:true,Int64:int64(otherTTL)},
127+
})
128+
129+
// Ensure the workspace's start with the correct TTLs
130+
require.Equal(t, sql.NullInt64{Valid:true,Int64:int64(tt.fromTTL)},workspace.Ttl)
131+
require.Equal(t, sql.NullInt64{Valid:true,Int64:int64(otherTTL)},otherWorkspace.Ttl)
132+
133+
// Update _only_ the primary template's TTL
134+
_,err=templateScheduleStore.Set(ctx,db,template, schedule.TemplateScheduleOptions{
135+
DefaultTTL:tt.toTTL,
136+
})
137+
require.NoError(t,err)
138+
139+
// Verify the primary workspace's TTL has been updated.
140+
ws,err:=db.GetWorkspaceByID(ctx,workspace.ID)
141+
require.NoError(t,err)
142+
require.Equal(t,tt.expected,ws.Ttl)
143+
144+
// Verify that the other workspace's TTL has not been touched.
145+
ws,err=db.GetWorkspaceByID(ctx,otherWorkspace.ID)
146+
require.NoError(t,err)
147+
require.Equal(t, sql.NullInt64{Valid:true,Int64:int64(otherTTL)},ws.Ttl)
148+
})
149+
}
150+
}

‎enterprise/coderd/schedule/template.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,23 @@ func (s *EnterpriseTemplateScheduleStore) Set(ctx context.Context, db database.S
195195
returnxerrors.Errorf("get updated template schedule: %w",err)
196196
}
197197

198+
// Update all workspace's TTL using this template if either of the following:
199+
// - The template's AllowUserAutostop has just been disabled
200+
// - The template's TTL has been modified and AllowUserAutostop is disabled
201+
if!opts.UserAutostopEnabled&& (tpl.AllowUserAutostop||int64(opts.DefaultTTL)!=tpl.DefaultTTL) {
202+
varttl sql.NullInt64
203+
ifopts.DefaultTTL!=0 {
204+
ttl= sql.NullInt64{Valid:true,Int64:int64(opts.DefaultTTL)}
205+
}
206+
207+
iferr=tx.UpdateWorkspacesTTLByTemplateID(ctx, database.UpdateWorkspacesTTLByTemplateIDParams{
208+
TemplateID:template.ID,
209+
Ttl:ttl,
210+
});err!=nil {
211+
returnxerrors.Errorf("update workspaces ttl by template id %q: %w",template.ID,err)
212+
}
213+
}
214+
198215
// Recalculate max_deadline and deadline for all running workspace
199216
// builds on this template.
200217
err=s.updateWorkspaceBuilds(ctx,tx,template)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp