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

feat: implement claiming of prebuilt workspaces#17458

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
evgeniy-scherbina merged 38 commits intomainfromyevhenii/512-claim-prebuild
Apr 24, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
38 commits
Select commitHold shift + click to select a range
8b9e30d
feat: implement claiming of prebuilt workspaces
evgeniy-scherbinaApr 17, 2025
d9497df
Merge branch 'main' of github.com:/coder/coder into yevhenii/512-clai…
dannykoppingApr 22, 2025
217e46f
Reverting unncessary changes
dannykoppingApr 21, 2025
c459533
Refactoring
dannykoppingApr 22, 2025
f905219
Removing unnecessary field
dannykoppingApr 22, 2025
8266338
make fmt
dannykoppingApr 22, 2025
4098ed7
CR's fixes
evgeniy-scherbinaApr 22, 2025
50d23e4
CR's fixes
evgeniy-scherbinaApr 22, 2025
546b7ae
Update coderd/workspaces.go
evgeniy-scherbinaApr 22, 2025
85f7926
CR's fixes
evgeniy-scherbinaApr 22, 2025
ee9908c
CR's fixes
evgeniy-scherbinaApr 22, 2025
70bf179
CR's fixes
evgeniy-scherbinaApr 22, 2025
7a72d03
CR's fixes
evgeniy-scherbinaApr 22, 2025
b246589
fix tests by updating noop.go
evgeniy-scherbinaApr 22, 2025
ff8d3de
Merge branch 'main' of github.com:/coder/coder into yevhenii/512-clai…
dannykoppingApr 23, 2025
fcdbba8
test: add failure testcase scenario
evgeniy-scherbinaApr 23, 2025
e7b7f80
refactor: revert interface changes
evgeniy-scherbinaApr 23, 2025
e7455db
refactor: simplify signature of claim method
evgeniy-scherbinaApr 23, 2025
077d7f0
refactor: CR's fixes
evgeniy-scherbinaApr 23, 2025
0d426c7
Merge remote-tracking branch 'origin/main' into yevhenii/512-claim-pr…
evgeniy-scherbinaApr 23, 2025
663a8c0
refactor: CR's fixes
evgeniy-scherbinaApr 23, 2025
bc31fac
refactor: make lint
evgeniy-scherbinaApr 23, 2025
087bd20
refactor: fix linter
evgeniy-scherbinaApr 23, 2025
9f66169
refactor: remove PrebuildsOrchestrator context from claim tests
evgeniy-scherbinaApr 23, 2025
7f25f24
refactor: don't fail test in a goroutine
evgeniy-scherbinaApr 23, 2025
ff9eeb4
docs: fix ssh coder example in testing-templates doc (#17550)
EdwardAngertApr 23, 2025
31b873f
fix: add websocket close handling (#17548)
jaaydenhApr 23, 2025
4fe770d
ci: move go install tools to separate action (#17552)
ethanndicksonApr 24, 2025
8d8fc99
chore(dogfood): allow provider minor version updates (#17554)
matifaliApr 24, 2025
af32325
fix(examples/templates/docker-devcontainer): update folder path and p…
AericioApr 24, 2025
0826e8a
feat: enable masking password inputs instead of blocking echo (#17469)
ibetitsmikeApr 24, 2025
cbb6c12
fix(examples/templates/kubernetes-devcontainer): update coder provide…
matifaliApr 24, 2025
e466844
docs: add automatic release calendar updates in docs (#17531)
matifaliApr 24, 2025
f24557b
chore(dogfood): add windsurf module (#17558)
matifaliApr 24, 2025
fa65564
Merge branch 'main' of github.com:/coder/coder into yevhenii/512-clai…
dannykoppingApr 24, 2025
53b38d7
fix: use userCtx instead of prebuildCtx for claiming prebuild
evgeniy-scherbinaApr 24, 2025
6c41e03
refactor: CR's fixes
evgeniy-scherbinaApr 24, 2025
9173e9a
CR's fixes
evgeniy-scherbinaApr 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletionscoderd/coderd.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,7 @@ import (
"github.com/coder/coder/v2/coderd/entitlements"
"github.com/coder/coder/v2/coderd/files"
"github.com/coder/coder/v2/coderd/idpsync"
"github.com/coder/coder/v2/coderd/prebuilds"
"github.com/coder/coder/v2/coderd/runtimeconfig"
"github.com/coder/coder/v2/coderd/webpush"

Expand DownExpand Up@@ -595,6 +596,7 @@ func New(options *Options) *API {
f := appearance.NewDefaultFetcher(api.DeploymentValues.DocsURL.String())
api.AppearanceFetcher.Store(&f)
api.PortSharer.Store(&portsharing.DefaultPortSharer)
api.PrebuildsClaimer.Store(&prebuilds.DefaultClaimer)
buildInfo := codersdk.BuildInfoResponse{
ExternalURL: buildinfo.ExternalURL(),
Version: buildinfo.Version(),
Expand DownExpand Up@@ -1569,6 +1571,7 @@ type API struct {
AccessControlStore *atomic.Pointer[dbauthz.AccessControlStore]
PortSharer atomic.Pointer[portsharing.PortSharer]
FileCache files.Cache
PrebuildsClaimer atomic.Pointer[prebuilds.Claimer]

UpdatesProvider tailnet.WorkspaceUpdatesProvider

Expand Down
10 changes: 10 additions & 0 deletionscoderd/prebuilds/api.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,8 +2,13 @@ package prebuilds

import (
"context"

"github.com/google/uuid"
"golang.org/x/xerrors"
)

var ErrNoClaimablePrebuiltWorkspaces = xerrors.New("no claimable prebuilt workspaces found")

// 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 {
Expand All@@ -25,3 +30,8 @@ type Reconciler interface {
// in parallel, creating or deleting prebuilds as needed to reach their desired states.
ReconcileAll(ctx context.Context) error
}

type Claimer interface {
Claim(ctx context.Context, userID uuid.UUID, name string, presetID uuid.UUID) (*uuid.UUID, error)
Initiator() uuid.UUID
}
15 changes: 15 additions & 0 deletionscoderd/prebuilds/noop.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,6 +3,8 @@ package prebuilds
import (
"context"

"github.com/google/uuid"

"github.com/coder/coder/v2/coderd/database"
)

Expand DownExpand Up@@ -33,3 +35,16 @@ func (NoopReconciler) CalculateActions(context.Context, PresetSnapshot) (*Reconc
}

var _ ReconciliationOrchestrator = NoopReconciler{}

type AGPLPrebuildClaimer struct{}

func (AGPLPrebuildClaimer) Claim(context.Context, uuid.UUID, string, uuid.UUID) (*uuid.UUID, error) {
// Not entitled to claim prebuilds in AGPL version.
return nil, ErrNoClaimablePrebuiltWorkspaces
}

func (AGPLPrebuildClaimer) Initiator() uuid.UUID {
return uuid.Nil
}

var DefaultClaimer Claimer = AGPLPrebuildClaimer{}
9 changes: 5 additions & 4 deletionscoderd/provisionerdserver/provisionerdserver.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2471,10 +2471,11 @@ type TemplateVersionImportJob struct {

// WorkspaceProvisionJob is the payload for the "workspace_provision" job type.
type WorkspaceProvisionJob struct {
WorkspaceBuildID uuid.UUID `json:"workspace_build_id"`
DryRun bool `json:"dry_run"`
IsPrebuild bool `json:"is_prebuild,omitempty"`
LogLevel string `json:"log_level,omitempty"`
WorkspaceBuildID uuid.UUID `json:"workspace_build_id"`
DryRun bool `json:"dry_run"`
IsPrebuild bool `json:"is_prebuild,omitempty"`
PrebuildClaimedByUser uuid.UUID `json:"prebuild_claimed_by,omitempty"`
LogLevel string `json:"log_level,omitempty"`
}

// TemplateVersionDryRunJob is the payload for the "template_version_dry_run" job type.
Expand Down
90 changes: 69 additions & 21 deletionscoderd/workspaces.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,6 +18,7 @@ import (
"golang.org/x/xerrors"

"cdr.dev/slog"

"github.com/coder/coder/v2/agent/proto"
"github.com/coder/coder/v2/coderd/audit"
"github.com/coder/coder/v2/coderd/database"
Expand All@@ -28,6 +29,7 @@ import (
"github.com/coder/coder/v2/coderd/httpapi"
"github.com/coder/coder/v2/coderd/httpmw"
"github.com/coder/coder/v2/coderd/notifications"
"github.com/coder/coder/v2/coderd/prebuilds"
"github.com/coder/coder/v2/coderd/rbac"
"github.com/coder/coder/v2/coderd/rbac/policy"
"github.com/coder/coder/v2/coderd/schedule"
Expand DownExpand Up@@ -636,33 +638,57 @@ func createWorkspace(
workspaceBuild *database.WorkspaceBuild
provisionerDaemons []database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow
)

err = api.Database.InTx(func(db database.Store) error {
now := dbtime.Now()
// Workspaces are created without any versions.
minimumWorkspace, err := db.InsertWorkspace(ctx, database.InsertWorkspaceParams{
ID: uuid.New(),
CreatedAt: now,
UpdatedAt: now,
OwnerID: owner.ID,
OrganizationID: template.OrganizationID,
TemplateID: template.ID,
Name: req.Name,
AutostartSchedule: dbAutostartSchedule,
NextStartAt: nextStartAt,
Ttl: dbTTL,
// The workspaces page will sort by last used at, and it's useful to
// have the newly created workspace at the top of the list!
LastUsedAt: dbtime.Now(),
AutomaticUpdates: dbAU,
})
if err != nil {
return xerrors.Errorf("insert workspace: %w", err)
var (
workspaceID uuid.UUID
claimedWorkspace *database.Workspace
prebuildsClaimer = *api.PrebuildsClaimer.Load()
)

// If a template preset was chosen, try claim a prebuilt workspace.
if req.TemplateVersionPresetID != uuid.Nil {
// Try and claim an eligible prebuild, if available.
claimedWorkspace, err = claimPrebuild(ctx, prebuildsClaimer, db, api.Logger, req, owner)
if err != nil && !errors.Is(err, prebuilds.ErrNoClaimablePrebuiltWorkspaces) {
return xerrors.Errorf("claim prebuild: %w", err)
}
}

// No prebuild found; regular flow.
if claimedWorkspace == nil {
now := dbtime.Now()
// Workspaces are created without any versions.
minimumWorkspace, err := db.InsertWorkspace(ctx, database.InsertWorkspaceParams{
ID: uuid.New(),
CreatedAt: now,
UpdatedAt: now,
OwnerID: owner.ID,
OrganizationID: template.OrganizationID,
TemplateID: template.ID,
Name: req.Name,
AutostartSchedule: dbAutostartSchedule,
NextStartAt: nextStartAt,
Ttl: dbTTL,
// The workspaces page will sort by last used at, and it's useful to
// have the newly created workspace at the top of the list!
LastUsedAt: dbtime.Now(),
AutomaticUpdates: dbAU,
})
if err != nil {
return xerrors.Errorf("insert workspace: %w", err)
}
workspaceID = minimumWorkspace.ID
} else {
// Prebuild found!
workspaceID = claimedWorkspace.ID
initiatorID = prebuildsClaimer.Initiator()
}

// We have to refetch the workspace for the joined in fields.
// TODO: We can use WorkspaceTable for the builder to not require
// this extra fetch.
workspace, err = db.GetWorkspaceByID(ctx,minimumWorkspace.ID)
workspace, err = db.GetWorkspaceByID(ctx,workspaceID)
if err != nil {
return xerrors.Errorf("get workspace by ID: %w", err)
}
Expand All@@ -676,6 +702,13 @@ func createWorkspace(
if req.TemplateVersionID != uuid.Nil {
builder = builder.VersionID(req.TemplateVersionID)
}
if req.TemplateVersionPresetID != uuid.Nil {
builder = builder.TemplateVersionPresetID(req.TemplateVersionPresetID)
}
if claimedWorkspace != nil {
builder = builder.MarkPrebuildClaimedBy(owner.ID)
}

if req.EnableDynamicParameters && api.Experiments.Enabled(codersdk.ExperimentDynamicParameters) {
builder = builder.UsingDynamicParameters()
}
Expand DownExpand Up@@ -842,6 +875,21 @@ func requestTemplate(ctx context.Context, rw http.ResponseWriter, req codersdk.C
return template, true
}

func claimPrebuild(ctx context.Context, claimer prebuilds.Claimer, db database.Store, logger slog.Logger, req codersdk.CreateWorkspaceRequest, owner workspaceOwner) (*database.Workspace, error) {
claimedID, err := claimer.Claim(ctx, owner.ID, req.Name, req.TemplateVersionPresetID)
if err != nil {
// TODO: enhance this by clarifying whether this *specific* prebuild failed or whether there are none to claim.
return nil, xerrors.Errorf("claim prebuild: %w", err)
}

lookup, err := db.GetWorkspaceByID(ctx, *claimedID)
if err != nil {
logger.Error(ctx, "unable to find claimed workspace by ID", slog.Error(err), slog.F("claimed_prebuild_id", claimedID.String()))
return nil, xerrors.Errorf("find claimed workspace by ID %q: %w", claimedID.String(), err)
}
return &lookup, nil
}

func (api *API) notifyWorkspaceCreated(
ctx context.Context,
receiverID uuid.UUID,
Expand Down
16 changes: 12 additions & 4 deletionscoderd/wsbuilder/wsbuilder.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -76,7 +76,8 @@ type Builder struct {
parameterValues *[]string
templateVersionPresetParameterValues []database.TemplateVersionPresetParameter

prebuild bool
prebuild bool
prebuildClaimedBy uuid.UUID

verifyNoLegacyParametersOnce bool
}
Expand DownExpand Up@@ -179,6 +180,12 @@ func (b Builder) MarkPrebuild() Builder {
return b
}

func (b Builder) MarkPrebuildClaimedBy(userID uuid.UUID) Builder {
// nolint: revive
b.prebuildClaimedBy = userID
return b
}

func (b Builder) UsingDynamicParameters() Builder {
b.dynamicParametersEnabled = true
return b
Expand DownExpand Up@@ -315,9 +322,10 @@ func (b *Builder) buildTx(authFunc func(action policy.Action, object rbac.Object

workspaceBuildID := uuid.New()
input, err := json.Marshal(provisionerdserver.WorkspaceProvisionJob{
WorkspaceBuildID: workspaceBuildID,
LogLevel: b.logLevel,
IsPrebuild: b.prebuild,
WorkspaceBuildID: workspaceBuildID,
LogLevel: b.logLevel,
IsPrebuild: b.prebuild,
PrebuildClaimedByUser: b.prebuildClaimedBy,
})
if err != nil {
return nil, nil, nil, BuildError{
Expand Down
53 changes: 53 additions & 0 deletionsenterprise/coderd/prebuilds/claim.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
package prebuilds

import (
"context"
"database/sql"
"errors"

"github.com/google/uuid"
"golang.org/x/xerrors"

"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/prebuilds"
)

type EnterpriseClaimer struct {
store database.Store
}

func NewEnterpriseClaimer(store database.Store) *EnterpriseClaimer {
return &EnterpriseClaimer{
store: store,
}
}

func (c EnterpriseClaimer) Claim(
ctx context.Context,
userID uuid.UUID,
name string,
presetID uuid.UUID,
) (*uuid.UUID, error) {
result, err := c.store.ClaimPrebuiltWorkspace(ctx, database.ClaimPrebuiltWorkspaceParams{
NewUserID: userID,
NewName: name,
PresetID: presetID,
})
if err != nil {
switch {
// No eligible prebuilds found
case errors.Is(err, sql.ErrNoRows):
return nil, prebuilds.ErrNoClaimablePrebuiltWorkspaces
default:
return nil, xerrors.Errorf("claim prebuild for user %q: %w", userID.String(), err)
}
}

return &result.ID, nil
}

func (EnterpriseClaimer) Initiator() uuid.UUID {
return prebuilds.SystemUserID
}

var _ prebuilds.Claimer = &EnterpriseClaimer{}
Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp