mirror of
https://github.com/coder/coder.git
synced 2026-06-04 13:38:21 +00:00
8567ecbe52
## 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.
71 lines
2.6 KiB
Go
71 lines
2.6 KiB
Go
package prebuilds
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/coder/coder/v2/coderd/database"
|
|
sdkproto "github.com/coder/coder/v2/provisionersdk/proto"
|
|
)
|
|
|
|
var (
|
|
ErrNoClaimablePrebuiltWorkspaces = xerrors.New("no claimable prebuilt workspaces found")
|
|
ErrAGPLDoesNotSupportPrebuiltWorkspaces = xerrors.New("prebuilt workspaces functionality is not supported under the AGPL license")
|
|
)
|
|
|
|
// ReconciliationOrchestrator manages the lifecycle of prebuild reconciliation.
|
|
// It runs a continuous loop to check and reconcile prebuild states, and can be stopped gracefully.
|
|
type ReconciliationOrchestrator interface {
|
|
Reconciler
|
|
|
|
// Run starts a continuous reconciliation loop that periodically calls ReconcileAll
|
|
// to ensure all prebuilds are in their desired states. The loop runs until the context
|
|
// is canceled or Stop is called.
|
|
Run(ctx context.Context)
|
|
|
|
// Stop gracefully shuts down the orchestrator with the given cause.
|
|
// The cause is used for logging and error reporting.
|
|
Stop(ctx context.Context, cause error)
|
|
|
|
// TrackResourceReplacement handles a pathological situation whereby a terraform resource is replaced due to drift,
|
|
// which can obviate the whole point of pre-provisioning a prebuilt workspace.
|
|
// See more detail at https://coder.com/docs/admin/templates/extending-templates/prebuilt-workspaces#preventing-resource-replacement.
|
|
TrackResourceReplacement(ctx context.Context, workspaceID, buildID uuid.UUID, replacements []*sdkproto.ResourceReplacement)
|
|
}
|
|
|
|
type Reconciler interface {
|
|
StateSnapshotter
|
|
|
|
// ReconcileAll orchestrates the reconciliation of all prebuilds across all templates.
|
|
// It takes a global snapshot of the system state and then reconciles each preset
|
|
// in parallel, creating or deleting prebuilds as needed to reach their desired states.
|
|
ReconcileAll(ctx context.Context) error
|
|
}
|
|
|
|
// StateSnapshotter defines the operations necessary to capture workspace prebuilds state.
|
|
type StateSnapshotter interface {
|
|
// SnapshotState captures the current state of all prebuilds across templates.
|
|
// It creates a global database snapshot that can be viewed as a collection of PresetSnapshots,
|
|
// each representing the state of prebuilds for a specific preset.
|
|
// MUST be called inside a repeatable-read transaction.
|
|
SnapshotState(ctx context.Context, store database.Store) (*GlobalSnapshot, error)
|
|
}
|
|
|
|
type Claimer interface {
|
|
Claim(
|
|
ctx context.Context,
|
|
now time.Time,
|
|
userID uuid.UUID,
|
|
name string,
|
|
presetID uuid.UUID,
|
|
autostartSchedule sql.NullString,
|
|
nextStartAt sql.NullTime,
|
|
ttl sql.NullInt64,
|
|
) (*uuid.UUID, error)
|
|
Initiator() uuid.UUID
|
|
}
|