postWorkspaceBuildsInternal handles the internal logic for creating workspace builds, can be called by other handlers and must not reference httpmw.
( ctx context.Context, apiKey database.APIKey, workspace database.Workspace, createBuild codersdk.CreateWorkspaceBuildRequest, authorize func(action policy.Action, object rbac.Objecter) bool, workspaceBuildBaggage audit.WorkspaceBuildBaggage, )
| 365 | // workspace builds, can be called by other handlers and must not |
| 366 | // reference httpmw. |
| 367 | func (api *API) postWorkspaceBuildsInternal( |
| 368 | ctx context.Context, |
| 369 | apiKey database.APIKey, |
| 370 | workspace database.Workspace, |
| 371 | createBuild codersdk.CreateWorkspaceBuildRequest, |
| 372 | authorize func(action policy.Action, object rbac.Objecter) bool, |
| 373 | workspaceBuildBaggage audit.WorkspaceBuildBaggage, |
| 374 | ) ( |
| 375 | codersdk.WorkspaceBuild, |
| 376 | error, |
| 377 | ) { |
| 378 | transition := database.WorkspaceTransition(createBuild.Transition) |
| 379 | builder := wsbuilder.New(workspace, transition, *api.BuildUsageChecker.Load()). |
| 380 | Initiator(apiKey.UserID). |
| 381 | RichParameterValues(createBuild.RichParameterValues). |
| 382 | LogLevel(string(createBuild.LogLevel)). |
| 383 | DeploymentValues(api.Options.DeploymentValues). |
| 384 | Experiments(api.Experiments). |
| 385 | TemplateVersionPresetID(createBuild.TemplateVersionPresetID). |
| 386 | BuildMetrics(api.WorkspaceBuilderMetrics) |
| 387 | |
| 388 | if (transition == database.WorkspaceTransitionStart || transition == database.WorkspaceTransitionStop) && createBuild.Reason != "" { |
| 389 | builder = builder.Reason(database.BuildReason(createBuild.Reason)) |
| 390 | } |
| 391 | |
| 392 | var ( |
| 393 | previousWorkspaceBuild database.WorkspaceBuild |
| 394 | workspaceBuild *database.WorkspaceBuild |
| 395 | provisionerJob *database.ProvisionerJob |
| 396 | provisionerDaemons []database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow |
| 397 | ) |
| 398 | |
| 399 | err := api.Database.InTx(func(tx database.Store) error { |
| 400 | var err error |
| 401 | |
| 402 | // #20925: if the workspace is dormant and we are starting the workspace, |
| 403 | // we need to unset that status before inserting a new build. |
| 404 | // This is done inside the transaction for consistency, but it could also be |
| 405 | // done outside the transaction so that an attempt to start a workspace will |
| 406 | // also unset dormancy. |
| 407 | if workspace.DormantAt.Valid && transition == database.WorkspaceTransitionStart { |
| 408 | if _, err := tx.UpdateWorkspaceDormantDeletingAt(ctx, database.UpdateWorkspaceDormantDeletingAtParams{ |
| 409 | ID: workspace.ID, |
| 410 | DormantAt: sql.NullTime{Valid: false}, |
| 411 | }); err != nil { |
| 412 | return httperror.NewResponseError(http.StatusInternalServerError, codersdk.Response{ |
| 413 | Message: "Internal error unsetting workspace dormant status", |
| 414 | Detail: err.Error(), |
| 415 | }) |
| 416 | } |
| 417 | // We need to audit this change separately. |
| 418 | updatedWorkspace := workspace.WorkspaceTable() |
| 419 | updatedWorkspace.DormantAt = sql.NullTime{Valid: false} |
| 420 | auditor := api.Auditor.Load() |
| 421 | bag := audit.BaggageFromContext(ctx) |
| 422 | audit.BackgroundAudit(ctx, &audit.BackgroundAuditParams[database.WorkspaceTable]{ |
| 423 | Audit: *auditor, |
| 424 | Old: workspace.WorkspaceTable(), |
no test coverage detected