mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix: set prebuilds lifecycle parameters on creation and claim (#19252)
## Description This PR ensures that prebuilt workspaces are properly excluded from the lifecycle executor and treated as a separate class of workspaces, fully managed by the prebuild reconciliation loop. It introduces two lifecycle guarantees: * When a prebuilt workspace is created (i.e., when the workspace build completes), all lifecycle-related fields are unset, ensuring the workspace does not participate in TTL, autostop, autostart, dormancy, or auto-deletion logic. * When a prebuilt workspace is claimed, it transitions into a regular user workspace. At this point, all lifecycle fields are correctly populated according to template-level configurations, allowing the workspace to be managed by the lifecycle executor as expected. ## Changes * Prebuilt workspaces now have all lifecycle-relevant fields unset during creation * When a prebuild is claimed: * Lifecycle fields are set based on template and workspace level configurations. This ensures a clean transition into the standard workspace lifecycle flow. * Updated lifecycle-related SQL update queries to explicitly exclude prebuilt workspaces. ## Relates Related issue: https://github.com/coder/coder/issues/18898 To reduce the scope of this PR and make the review process more manageable, the original implementation has been split into the following focused PRs: * https://github.com/coder/coder/pull/19259 * https://github.com/coder/coder/pull/19263 * https://github.com/coder/coder/pull/19264 * https://github.com/coder/coder/pull/19265 These PRs should be considered in conjunction with this one to understand the complete set of lifecycle separation changes for prebuilt workspaces.
This commit is contained in:
@@ -1251,7 +1251,7 @@ func TestExecutorPrebuilds(t *testing.T) {
|
||||
}()
|
||||
|
||||
// Then: the prebuilt workspace should remain in a start transition
|
||||
prebuildStats := <-statsCh
|
||||
prebuildStats := testutil.RequireReceive(ctx, t, statsCh)
|
||||
require.Len(t, prebuildStats.Errors, 0)
|
||||
require.Len(t, prebuildStats.Transitions, 0)
|
||||
require.Equal(t, codersdk.WorkspaceTransitionStart, prebuild.LatestBuild.Transition)
|
||||
@@ -1259,7 +1259,15 @@ func TestExecutorPrebuilds(t *testing.T) {
|
||||
require.Equal(t, codersdk.BuildReasonInitiator, prebuild.LatestBuild.Reason)
|
||||
|
||||
// Given: a user claims the prebuilt workspace
|
||||
dbWorkspace := dbgen.ClaimPrebuild(t, db, user.ID, "claimedWorkspace-autostop", preset.ID)
|
||||
dbWorkspace := dbgen.ClaimPrebuild(
|
||||
t, db,
|
||||
clock.Now(),
|
||||
user.ID,
|
||||
"claimedWorkspace-autostop",
|
||||
preset.ID,
|
||||
sql.NullString{},
|
||||
sql.NullTime{},
|
||||
sql.NullInt64{})
|
||||
workspace := coderdtest.MustWorkspace(t, client, dbWorkspace.ID)
|
||||
|
||||
// When: the autobuild executor ticks *after* the deadline:
|
||||
@@ -1269,7 +1277,7 @@ func TestExecutorPrebuilds(t *testing.T) {
|
||||
}()
|
||||
|
||||
// Then: the workspace should be stopped
|
||||
workspaceStats := <-statsCh
|
||||
workspaceStats := testutil.RequireReceive(ctx, t, statsCh)
|
||||
require.Len(t, workspaceStats.Errors, 0)
|
||||
require.Len(t, workspaceStats.Transitions, 1)
|
||||
require.Contains(t, workspaceStats.Transitions, workspace.ID)
|
||||
@@ -1336,7 +1344,7 @@ func TestExecutorPrebuilds(t *testing.T) {
|
||||
}()
|
||||
|
||||
// Then: the prebuilt workspace should remain in a stop transition
|
||||
prebuildStats := <-statsCh
|
||||
prebuildStats := testutil.RequireReceive(ctx, t, statsCh)
|
||||
require.Len(t, prebuildStats.Errors, 0)
|
||||
require.Len(t, prebuildStats.Transitions, 0)
|
||||
require.Equal(t, codersdk.WorkspaceTransitionStop, prebuild.LatestBuild.Transition)
|
||||
@@ -1353,7 +1361,15 @@ func TestExecutorPrebuilds(t *testing.T) {
|
||||
database.WorkspaceTransitionStart)
|
||||
|
||||
// Given: a user claims the prebuilt workspace
|
||||
dbWorkspace := dbgen.ClaimPrebuild(t, db, user.ID, "claimedWorkspace-autostart", preset.ID)
|
||||
dbWorkspace := dbgen.ClaimPrebuild(
|
||||
t, db,
|
||||
clock.Now(),
|
||||
user.ID,
|
||||
"claimedWorkspace-autostart",
|
||||
preset.ID,
|
||||
autostartSched,
|
||||
sql.NullTime{},
|
||||
sql.NullInt64{})
|
||||
workspace := coderdtest.MustWorkspace(t, client, dbWorkspace.ID)
|
||||
|
||||
// Given: the prebuilt workspace goes to a stop status
|
||||
@@ -1374,7 +1390,7 @@ func TestExecutorPrebuilds(t *testing.T) {
|
||||
}()
|
||||
|
||||
// Then: the workspace should eventually be started
|
||||
workspaceStats := <-statsCh
|
||||
workspaceStats := testutil.RequireReceive(ctx, t, statsCh)
|
||||
require.Len(t, workspaceStats.Errors, 0)
|
||||
require.Len(t, workspaceStats.Transitions, 1)
|
||||
require.Contains(t, workspaceStats.Transitions, workspace.ID)
|
||||
@@ -1486,8 +1502,8 @@ func setupTestDBWorkspaceBuild(
|
||||
Architecture: "i386",
|
||||
OperatingSystem: "linux",
|
||||
LifecycleState: database.WorkspaceAgentLifecycleStateReady,
|
||||
StartedAt: sql.NullTime{Time: time.Now().Add(time.Hour), Valid: true},
|
||||
ReadyAt: sql.NullTime{Time: time.Now().Add(-1 * time.Hour), Valid: true},
|
||||
StartedAt: sql.NullTime{Time: clock.Now().Add(time.Hour), Valid: true},
|
||||
ReadyAt: sql.NullTime{Time: clock.Now().Add(-1 * time.Hour), Valid: true},
|
||||
APIKeyScope: database.AgentKeyScopeEnumAll,
|
||||
})
|
||||
|
||||
@@ -1524,8 +1540,9 @@ func setupTestDBPrebuiltWorkspace(
|
||||
OrganizationID: orgID,
|
||||
OwnerID: database.PrebuildsSystemUserID,
|
||||
Deleted: false,
|
||||
CreatedAt: time.Now().Add(-time.Hour * 2),
|
||||
CreatedAt: clock.Now().Add(-time.Hour * 2),
|
||||
AutostartSchedule: options.AutostartSchedule,
|
||||
LastUsedAt: clock.Now(),
|
||||
})
|
||||
setupTestDBWorkspaceBuild(ctx, t, clock, db, ps, orgID, workspace.ID, templateVersionID, presetID, buildTransition)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user