@@ -18,6 +18,7 @@ import (
1818
1919 "cdr.dev/slog"
2020
21+ "github.com/coder/coder/v2/coderd/prebuilds"
2122 "github.com/coder/coder/v2/coderd/rbac/policy"
2223 "github.com/coder/coder/v2/coderd/rbac/rolestore"
2324
@@ -361,6 +362,27 @@ var (
361362 }),
362363 Scope : rbac .ScopeAll ,
363364 }.WithCachedASTValue ()
365+
366+ subjectPrebuildsOrchestrator = rbac.Subject {
367+ FriendlyName : "Prebuilds Orchestrator" ,
368+ ID : prebuilds .SystemUserID .String (),
369+ Roles : rbac .Roles ([]rbac.Role {
370+ {
371+ Identifier : rbac.RoleIdentifier {Name : "prebuilds-orchestrator" },
372+ DisplayName : "Coder" ,
373+ Site : rbac .Permissions (map [string ][]policy.Action {
374+ // May use template, read template-related info, & insert template-related resources (preset prebuilds).
375+ rbac .ResourceTemplate .Type : {policy .ActionRead , policy .ActionUpdate , policy .ActionUse , policy .ActionViewInsights },
376+ // May CRUD workspaces, and start/stop them.
377+ rbac .ResourceWorkspace .Type : {
378+ policy .ActionCreate , policy .ActionDelete , policy .ActionRead , policy .ActionUpdate ,
379+ policy .ActionWorkspaceStart , policy .ActionWorkspaceStop ,
380+ },
381+ }),
382+ },
383+ }),
384+ Scope : rbac .ScopeAll ,
385+ }.WithCachedASTValue ()
364386)
365387
366388// AsProvisionerd returns a context with an actor that has permissions required
@@ -415,6 +437,12 @@ func AsSystemReadProvisionerDaemons(ctx context.Context) context.Context {
415437 return context .WithValue (ctx , authContextKey {}, subjectSystemReadProvisionerDaemons )
416438}
417439
440+ // AsPrebuildsOrchestrator returns a context with an actor that has permissions
441+ // to read orchestrator workspace prebuilds.
442+ func AsPrebuildsOrchestrator (ctx context.Context ) context.Context {
443+ return context .WithValue (ctx , authContextKey {}, subjectPrebuildsOrchestrator )
444+ }
445+
418446var AsRemoveActor = rbac.Subject {
419447 ID : "remove-actor" ,
420448}
@@ -1109,6 +1137,31 @@ func (q *querier) BulkMarkNotificationMessagesSent(ctx context.Context, arg data
11091137 return q .db .BulkMarkNotificationMessagesSent (ctx , arg )
11101138}
11111139
1140+ func (q * querier ) ClaimPrebuiltWorkspace (ctx context.Context , arg database.ClaimPrebuiltWorkspaceParams ) (database.ClaimPrebuiltWorkspaceRow , error ) {
1141+ empty := database.ClaimPrebuiltWorkspaceRow {}
1142+
1143+ preset , err := q .db .GetPresetByID (ctx , arg .PresetID )
1144+ if err != nil {
1145+ return empty , err
1146+ }
1147+
1148+ workspaceObject := rbac .ResourceWorkspace .WithOwner (arg .NewUserID .String ()).InOrg (preset .OrganizationID )
1149+ err = q .authorizeContext (ctx , policy .ActionCreate , workspaceObject .RBACObject ())
1150+ if err != nil {
1151+ return empty , err
1152+ }
1153+
1154+ tpl , err := q .GetTemplateByID (ctx , preset .TemplateID .UUID )
1155+ if err != nil {
1156+ return empty , xerrors .Errorf ("verify template by id: %w" , err )
1157+ }
1158+ if err := q .authorizeContext (ctx , policy .ActionUse , tpl ); err != nil {
1159+ return empty , xerrors .Errorf ("use template for workspace: %w" , err )
1160+ }
1161+
1162+ return q .db .ClaimPrebuiltWorkspace (ctx , arg )
1163+ }
1164+
11121165func (q * querier ) CleanTailnetCoordinators (ctx context.Context ) error {
11131166 if err := q .authorizeContext (ctx , policy .ActionDelete , rbac .ResourceTailnetCoordinator ); err != nil {
11141167 return err
@@ -1130,6 +1183,13 @@ func (q *querier) CleanTailnetTunnels(ctx context.Context) error {
11301183 return q .db .CleanTailnetTunnels (ctx )
11311184}
11321185
1186+ func (q * querier ) CountInProgressPrebuilds (ctx context.Context ) ([]database.CountInProgressPrebuildsRow , error ) {
1187+ if err := q .authorizeContext (ctx , policy .ActionRead , rbac .ResourceWorkspace .All ()); err != nil {
1188+ return nil , err
1189+ }
1190+ return q .db .CountInProgressPrebuilds (ctx )
1191+ }
1192+
11331193func (q * querier ) CountUnreadInboxNotificationsByUserID (ctx context.Context , userID uuid.UUID ) (int64 , error ) {
11341194 if err := q .authorizeContext (ctx , policy .ActionRead , rbac .ResourceInboxNotification .WithOwner (userID .String ())); err != nil {
11351195 return 0 , err
@@ -2096,6 +2156,30 @@ func (q *querier) GetParameterSchemasByJobID(ctx context.Context, jobID uuid.UUI
20962156 return q .db .GetParameterSchemasByJobID (ctx , jobID )
20972157}
20982158
2159+ func (q * querier ) GetPrebuildMetrics (ctx context.Context ) ([]database.GetPrebuildMetricsRow , error ) {
2160+ // GetPrebuildMetrics returns metrics related to prebuilt workspaces,
2161+ // such as the number of created and failed prebuilt workspaces.
2162+ if err := q .authorizeContext (ctx , policy .ActionRead , rbac .ResourceWorkspace .All ()); err != nil {
2163+ return nil , err
2164+ }
2165+ return q .db .GetPrebuildMetrics (ctx )
2166+ }
2167+
2168+ func (q * querier ) GetPresetByID (ctx context.Context , presetID uuid.UUID ) (database.GetPresetByIDRow , error ) {
2169+ empty := database.GetPresetByIDRow {}
2170+
2171+ preset , err := q .db .GetPresetByID (ctx , presetID )
2172+ if err != nil {
2173+ return empty , err
2174+ }
2175+ _ , err = q .GetTemplateByID (ctx , preset .TemplateID .UUID )
2176+ if err != nil {
2177+ return empty , err
2178+ }
2179+
2180+ return preset , nil
2181+ }
2182+
20992183func (q * querier ) GetPresetByWorkspaceBuildID (ctx context.Context , workspaceID uuid.UUID ) (database.TemplateVersionPreset , error ) {
21002184 if err := q .authorizeContext (ctx , policy .ActionRead , rbac .ResourceTemplate ); err != nil {
21012185 return database.TemplateVersionPreset {}, err
@@ -2113,6 +2197,14 @@ func (q *querier) GetPresetParametersByTemplateVersionID(ctx context.Context, te
21132197 return q .db .GetPresetParametersByTemplateVersionID (ctx , templateVersionID )
21142198}
21152199
2200+ func (q * querier ) GetPresetsBackoff (ctx context.Context , lookback time.Time ) ([]database.GetPresetsBackoffRow , error ) {
2201+ // GetPresetsBackoff returns a list of template version presets along with metadata such as the number of failed prebuilds.
2202+ if err := q .authorizeContext (ctx , policy .ActionViewInsights , rbac .ResourceTemplate .All ()); err != nil {
2203+ return nil , err
2204+ }
2205+ return q .db .GetPresetsBackoff (ctx , lookback )
2206+ }
2207+
21162208func (q * querier ) GetPresetsByTemplateVersionID (ctx context.Context , templateVersionID uuid.UUID ) ([]database.TemplateVersionPreset , error ) {
21172209 // An actor can read template version presets if they can read the related template version.
21182210 _ , err := q .GetTemplateVersionByID (ctx , templateVersionID )
@@ -2164,13 +2256,13 @@ func (q *querier) GetProvisionerJobByID(ctx context.Context, id uuid.UUID) (data
21642256 // can read the job.
21652257 _ , err := q .GetWorkspaceBuildByJobID (ctx , id )
21662258 if err != nil {
2167- return database.ProvisionerJob {}, err
2259+ return database.ProvisionerJob {}, xerrors . Errorf ( "fetch related workspace build: %w" , err )
21682260 }
21692261 case database .ProvisionerJobTypeTemplateVersionDryRun , database .ProvisionerJobTypeTemplateVersionImport :
21702262 // Authorized call to get template version.
21712263 _ , err := authorizedTemplateVersionFromJob (ctx , q , job )
21722264 if err != nil {
2173- return database.ProvisionerJob {}, err
2265+ return database.ProvisionerJob {}, xerrors . Errorf ( "fetch related template version: %w" , err )
21742266 }
21752267 default :
21762268 return database.ProvisionerJob {}, xerrors .Errorf ("unknown job type: %q" , job .Type )
@@ -2263,6 +2355,14 @@ func (q *querier) GetReplicasUpdatedAfter(ctx context.Context, updatedAt time.Ti
22632355 return q .db .GetReplicasUpdatedAfter (ctx , updatedAt )
22642356}
22652357
2358+ func (q * querier ) GetRunningPrebuiltWorkspaces (ctx context.Context ) ([]database.GetRunningPrebuiltWorkspacesRow , error ) {
2359+ // This query returns only prebuilt workspaces, but we decided to require permissions for all workspaces.
2360+ if err := q .authorizeContext (ctx , policy .ActionRead , rbac .ResourceWorkspace .All ()); err != nil {
2361+ return nil , err
2362+ }
2363+ return q .db .GetRunningPrebuiltWorkspaces (ctx )
2364+ }
2365+
22662366func (q * querier ) GetRuntimeConfig (ctx context.Context , key string ) (string , error ) {
22672367 if err := q .authorizeContext (ctx , policy .ActionRead , rbac .ResourceSystem ); err != nil {
22682368 return "" , err
@@ -2387,6 +2487,15 @@ func (q *querier) GetTemplateParameterInsights(ctx context.Context, arg database
23872487 return q .db .GetTemplateParameterInsights (ctx , arg )
23882488}
23892489
2490+ func (q * querier ) GetTemplatePresetsWithPrebuilds (ctx context.Context , templateID uuid.NullUUID ) ([]database.GetTemplatePresetsWithPrebuildsRow , error ) {
2491+ // GetTemplatePresetsWithPrebuilds retrieves template versions with configured presets and prebuilds.
2492+ // Presets and prebuilds are part of the template, so if you can access templates - you can access them as well.
2493+ if err := q .authorizeContext (ctx , policy .ActionRead , rbac .ResourceTemplate .All ()); err != nil {
2494+ return nil , err
2495+ }
2496+ return q .db .GetTemplatePresetsWithPrebuilds (ctx , templateID )
2497+ }
2498+
23902499func (q * querier ) GetTemplateUsageStats (ctx context.Context , arg database.GetTemplateUsageStatsParams ) ([]database.TemplateUsageStat , error ) {
23912500 if err := q .authorizeTemplateInsights (ctx , arg .TemplateIDs ); err != nil {
23922501 return nil , err
0 commit comments