Skip to content

Commit 02b26d1

Browse files
fix: allow agents to be created on dormant workspaces
Closes #20711 We now allow agents to be created on dormant workspaces.
1 parent 754ffb2 commit 02b26d1

File tree

2 files changed

+68
-1
lines changed

2 files changed

+68
-1
lines changed

coderd/database/dbauthz/dbauthz.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ var (
217217
rbac.ResourceTemplate.Type: {policy.ActionRead, policy.ActionUpdate},
218218
// Unsure why provisionerd needs update and read personal
219219
rbac.ResourceUser.Type: {policy.ActionRead, policy.ActionReadPersonal, policy.ActionUpdatePersonal},
220-
rbac.ResourceWorkspaceDormant.Type: {policy.ActionDelete, policy.ActionRead, policy.ActionUpdate, policy.ActionWorkspaceStop},
220+
rbac.ResourceWorkspaceDormant.Type: {policy.ActionDelete, policy.ActionRead, policy.ActionUpdate, policy.ActionWorkspaceStop, policy.ActionCreateAgent},
221221
rbac.ResourceWorkspace.Type: {policy.ActionDelete, policy.ActionRead, policy.ActionUpdate, policy.ActionWorkspaceStart, policy.ActionWorkspaceStop, policy.ActionCreateAgent},
222222
// Provisionerd needs to read, update, and delete tasks associated with workspaces.
223223
rbac.ResourceTask.Type: {policy.ActionRead, policy.ActionUpdate, policy.ActionDelete},

enterprise/coderd/workspaces_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,73 @@ func TestWorkspaceAutobuild(t *testing.T) {
831831
require.True(t, ws.LastUsedAt.After(dormantLastUsedAt))
832832
})
833833

834+
// This test has been added to ensure we don't introduce a regression
835+
// to this issue https://github.com/coder/coder/issues/20711.
836+
t.Run("DormantAutostop", func(t *testing.T) {
837+
t.Parallel()
838+
839+
var (
840+
ticker = make(chan time.Time)
841+
statCh = make(chan autobuild.Stats)
842+
inactiveTTL = time.Minute
843+
logger = slogtest.Make(t, &slogtest.Options{IgnoreErrors: true}).Leveled(slog.LevelDebug)
844+
)
845+
846+
client, db, user := coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
847+
Options: &coderdtest.Options{
848+
AutobuildTicker: ticker,
849+
AutobuildStats: statCh,
850+
IncludeProvisionerDaemon: true,
851+
TemplateScheduleStore: schedule.NewEnterpriseTemplateScheduleStore(agplUserQuietHoursScheduleStore(), notifications.NewNoopEnqueuer(), logger, nil),
852+
},
853+
LicenseOptions: &coderdenttest.LicenseOptions{
854+
Features: license.Features{codersdk.FeatureAdvancedTemplateScheduling: 1},
855+
},
856+
})
857+
858+
// Create a template version that includes agents on both start AND stop builds.
859+
// This simulates a template without `count = data.coder_workspace.me.start_count`.
860+
authToken := uuid.NewString()
861+
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
862+
Parse: echo.ParseComplete,
863+
ProvisionPlan: echo.PlanComplete,
864+
ProvisionApply: echo.ProvisionApplyWithAgent(authToken),
865+
})
866+
867+
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) {
868+
ctr.TimeTilDormantMillis = ptr.Ref[int64](inactiveTTL.Milliseconds())
869+
})
870+
871+
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
872+
ws := coderdtest.CreateWorkspace(t, client, template.ID)
873+
build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID)
874+
require.Equal(t, codersdk.WorkspaceStatusRunning, build.Status)
875+
876+
// Simulate the workspace becoming inactive and transitioning to dormant.
877+
tickTime := ws.LastUsedAt.Add(inactiveTTL * 2)
878+
879+
p, err := coderdtest.GetProvisionerForTags(db, time.Now(), ws.OrganizationID, nil)
880+
require.NoError(t, err)
881+
coderdtest.UpdateProvisionerLastSeenAt(t, db, p.ID, tickTime)
882+
ticker <- tickTime
883+
stats := <-statCh
884+
885+
// Expect workspace to transition to stopped state.
886+
require.Len(t, stats.Transitions, 1)
887+
require.Equal(t, stats.Transitions[ws.ID], database.WorkspaceTransitionStop)
888+
889+
// The autostop build should succeed even though the template includes
890+
// agents without `count = data.coder_workspace.me.start_count`.
891+
// This verifies that provisionerd has permission to create agents on
892+
// dormant workspaces during stop builds.
893+
ws = coderdtest.MustWorkspace(t, client, ws.ID)
894+
require.NotNil(t, ws.DormantAt, "workspace should be marked as dormant")
895+
require.Equal(t, codersdk.WorkspaceTransitionStop, ws.LatestBuild.Transition)
896+
897+
latestBuild := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID)
898+
require.Equal(t, codersdk.WorkspaceStatusStopped, latestBuild.Status)
899+
})
900+
834901
// This test serves as a regression prevention for generating
835902
// audit logs in the same transaction the transition workspaces to
836903
// the dormant state. The auditor that is passed to autobuild does

0 commit comments

Comments
 (0)