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

Commit8942b50

Browse files
authored
fix: allow unhanger to unhang dormant workspaces (#20229)
1 parentc84ab72 commit8942b50

File tree

4 files changed

+149
-5
lines changed

4 files changed

+149
-5
lines changed

‎coderd/database/dbauthz/dbauthz.go‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -274,10 +274,11 @@ var (
274274
Identifier: rbac.RoleIdentifier{Name:"jobreaper"},
275275
DisplayName:"Job Reaper Daemon",
276276
Site:rbac.Permissions(map[string][]policy.Action{
277-
rbac.ResourceSystem.Type: {policy.WildcardSymbol},
278-
rbac.ResourceTemplate.Type: {policy.ActionRead},
279-
rbac.ResourceWorkspace.Type: {policy.ActionRead,policy.ActionUpdate},
280-
rbac.ResourceProvisionerJobs.Type: {policy.ActionRead,policy.ActionUpdate},
277+
rbac.ResourceSystem.Type: {policy.WildcardSymbol},
278+
rbac.ResourceTemplate.Type: {policy.ActionRead,policy.ActionUpdate},
279+
rbac.ResourceWorkspace.Type: {policy.ActionRead,policy.ActionUpdate},
280+
rbac.ResourceWorkspaceDormant.Type: {policy.ActionRead,policy.ActionUpdate},
281+
rbac.ResourceProvisionerJobs.Type: {policy.ActionRead,policy.ActionUpdate},
281282
}),
282283
Org:map[string][]rbac.Permission{},
283284
User: []rbac.Permission{},

‎coderd/database/dbauthz/dbauthz_test.go‎

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1639,10 +1639,43 @@ func (s *MethodTestSuite) TestUser() {
16391639
}
16401640

16411641
func (s*MethodTestSuite)TestWorkspace() {
1642+
// The Workspace object differs it's type based on whether it's dormant or
1643+
// not, which is why we have two tests for it. To ensure we are actually
1644+
// testing the correct RBAC objects, we also explicitly create the expected
1645+
// object here rather than passing in the model.
16421646
s.Run("GetWorkspaceByID",s.Mocked(func(dbm*dbmock.MockStore,faker*gofakeit.Faker,check*expects) {
16431647
ws:=testutil.Fake(s.T(),faker, database.Workspace{})
1648+
ws.DormantAt= sql.NullTime{
1649+
Time: time.Time{},
1650+
Valid:false,
1651+
}
1652+
// Ensure the RBAC is not the dormant type.
1653+
require.Equal(s.T(),rbac.ResourceWorkspace.Type,ws.RBACObject().Type)
1654+
dbm.EXPECT().GetWorkspaceByID(gomock.Any(),ws.ID).Return(ws,nil).AnyTimes()
1655+
// Explicitly create the expected object.
1656+
expected:=rbac.ResourceWorkspace.WithID(ws.ID).
1657+
InOrg(ws.OrganizationID).
1658+
WithOwner(ws.OwnerID.String()).
1659+
WithGroupACL(ws.GroupACL.RBACACL()).
1660+
WithACLUserList(ws.UserACL.RBACACL())
1661+
check.Args(ws.ID).Asserts(expected,policy.ActionRead).Returns(ws)
1662+
}))
1663+
s.Run("DormantWorkspace/GetWorkspaceByID",s.Mocked(func(dbm*dbmock.MockStore,faker*gofakeit.Faker,check*expects) {
1664+
ws:=testutil.Fake(s.T(),faker, database.Workspace{
1665+
DormantAt: sql.NullTime{
1666+
Time:time.Now().Add(-time.Hour),
1667+
Valid:true,
1668+
},
1669+
})
1670+
// Ensure the RBAC changed automatically.
1671+
require.Equal(s.T(),rbac.ResourceWorkspaceDormant.Type,ws.RBACObject().Type)
16441672
dbm.EXPECT().GetWorkspaceByID(gomock.Any(),ws.ID).Return(ws,nil).AnyTimes()
1645-
check.Args(ws.ID).Asserts(ws,policy.ActionRead).Returns(ws)
1673+
// Explicitly create the expected object.
1674+
expected:=rbac.ResourceWorkspaceDormant.
1675+
WithID(ws.ID).
1676+
InOrg(ws.OrganizationID).
1677+
WithOwner(ws.OwnerID.String())
1678+
check.Args(ws.ID).Asserts(expected,policy.ActionRead).Returns(ws)
16461679
}))
16471680
s.Run("GetWorkspaceByResourceID",s.Mocked(func(dbm*dbmock.MockStore,faker*gofakeit.Faker,check*expects) {
16481681
ws:=testutil.Fake(s.T(),faker, database.Workspace{})

‎coderd/database/dbgen/dbgen.go‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,14 @@ func Workspace(t testing.TB, db database.Store, orig database.WorkspaceTable) da
420420
require.NoError(t,err,"set workspace as deleted")
421421
workspace.Deleted=true
422422
}
423+
iforig.DormantAt.Valid {
424+
_,err=db.UpdateWorkspaceDormantDeletingAt(genCtx, database.UpdateWorkspaceDormantDeletingAtParams{
425+
ID:workspace.ID,
426+
DormantAt:orig.DormantAt,
427+
})
428+
require.NoError(t,err,"set workspace as dormant")
429+
workspace.DormantAt=orig.DormantAt
430+
}
423431
returnworkspace
424432
}
425433

‎coderd/jobreaper/detector_test.go‎

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,108 @@ func TestDetectorPendingWorkspaceBuildNoOverrideStateIfNoExistingBuild(t *testin
533533
detector.Wait()
534534
}
535535

536+
// TestDetectorWorkspaceBuildForDormantWorkspace ensures that the jobreaper has
537+
// enough permissions to fix dormant workspaces.
538+
//
539+
// Dormant workspaces are treated as rbac.ResourceWorkspaceDormant rather than
540+
// rbac.ResourceWorkspace, which resulted in a bug where the jobreaper would
541+
// be able to see but not fix dormant workspaces.
542+
funcTestDetectorWorkspaceBuildForDormantWorkspace(t*testing.T) {
543+
t.Parallel()
544+
545+
var (
546+
ctx=testutil.Context(t,testutil.WaitLong)
547+
db,pubsub=dbtestutil.NewDB(t)
548+
log=testutil.Logger(t)
549+
tickCh=make(chan time.Time)
550+
statsCh=make(chan jobreaper.Stats)
551+
)
552+
553+
var (
554+
now=time.Now()
555+
tenMinAgo=now.Add(-time.Minute*10)
556+
sixMinAgo=now.Add(-time.Minute*6)
557+
org=dbgen.Organization(t,db, database.Organization{})
558+
user=dbgen.User(t,db, database.User{})
559+
file=dbgen.File(t,db, database.File{})
560+
template=dbgen.Template(t,db, database.Template{
561+
OrganizationID:org.ID,
562+
CreatedBy:user.ID,
563+
})
564+
templateVersion=dbgen.TemplateVersion(t,db, database.TemplateVersion{
565+
OrganizationID:org.ID,
566+
TemplateID: uuid.NullUUID{
567+
UUID:template.ID,
568+
Valid:true,
569+
},
570+
CreatedBy:user.ID,
571+
})
572+
workspace=dbgen.Workspace(t,db, database.WorkspaceTable{
573+
OwnerID:user.ID,
574+
OrganizationID:org.ID,
575+
TemplateID:template.ID,
576+
DormantAt: sql.NullTime{
577+
Time:now.Add(-time.Hour),
578+
Valid:true,
579+
},
580+
})
581+
582+
// First build.
583+
expectedWorkspaceBuildState= []byte(`{"dean":"cool","colin":"also cool"}`)
584+
currentWorkspaceBuildJob=dbgen.ProvisionerJob(t,db,pubsub, database.ProvisionerJob{
585+
CreatedAt:tenMinAgo,
586+
UpdatedAt:sixMinAgo,
587+
StartedAt: sql.NullTime{
588+
Time:tenMinAgo,
589+
Valid:true,
590+
},
591+
OrganizationID:org.ID,
592+
InitiatorID:user.ID,
593+
Provisioner:database.ProvisionerTypeEcho,
594+
StorageMethod:database.ProvisionerStorageMethodFile,
595+
FileID:file.ID,
596+
Type:database.ProvisionerJobTypeWorkspaceBuild,
597+
Input: []byte("{}"),
598+
})
599+
_=dbgen.WorkspaceBuild(t,db, database.WorkspaceBuild{
600+
WorkspaceID:workspace.ID,
601+
TemplateVersionID:templateVersion.ID,
602+
BuildNumber:1,
603+
JobID:currentWorkspaceBuildJob.ID,
604+
// Should not be overridden.
605+
ProvisionerState:expectedWorkspaceBuildState,
606+
})
607+
)
608+
609+
t.Log("current job ID: ",currentWorkspaceBuildJob.ID)
610+
611+
// Ensure the RBAC is the dormant type to ensure we're testing the right
612+
// thing.
613+
require.Equal(t,rbac.ResourceWorkspaceDormant.Type,workspace.RBACObject().Type)
614+
615+
detector:=jobreaper.New(ctx,wrapDBAuthz(db,log),pubsub,log,tickCh).WithStatsChannel(statsCh)
616+
detector.Start()
617+
tickCh<-now
618+
619+
stats:=<-statsCh
620+
require.NoError(t,stats.Error)
621+
require.Len(t,stats.TerminatedJobIDs,1)
622+
require.Equal(t,currentWorkspaceBuildJob.ID,stats.TerminatedJobIDs[0])
623+
624+
// Check that the current provisioner job was updated.
625+
job,err:=db.GetProvisionerJobByID(ctx,currentWorkspaceBuildJob.ID)
626+
require.NoError(t,err)
627+
require.WithinDuration(t,now,job.UpdatedAt,30*time.Second)
628+
require.True(t,job.CompletedAt.Valid)
629+
require.WithinDuration(t,now,job.CompletedAt.Time,30*time.Second)
630+
require.True(t,job.Error.Valid)
631+
require.Contains(t,job.Error.String,"Build has been detected as hung")
632+
require.False(t,job.ErrorCode.Valid)
633+
634+
detector.Close()
635+
detector.Wait()
636+
}
637+
536638
funcTestDetectorHungOtherJobTypes(t*testing.T) {
537639
t.Parallel()
538640

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp