Skip to content

Commit 81ba8d2

Browse files
SasSwartdannykopping
authored andcommitted
feat: add migrations and queries to support prebuilds
Signed-off-by: Danny Kopping <[email protected]>
1 parent 8e491d8 commit 81ba8d2

20 files changed

+1174
-4
lines changed

coderd/database/dbauthz/dbauthz.go

+84-2
Original file line numberDiff line numberDiff line change
@@ -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

@@ -358,6 +359,27 @@ var (
358359
}),
359360
Scope: rbac.ScopeAll,
360361
}.WithCachedASTValue()
362+
363+
subjectPrebuildsOrchestrator = rbac.Subject{
364+
FriendlyName: "Prebuilds Orchestrator",
365+
ID: prebuilds.OwnerID.String(),
366+
Roles: rbac.Roles([]rbac.Role{
367+
{
368+
Identifier: rbac.RoleIdentifier{Name: "prebuilds-orchestrator"},
369+
DisplayName: "Coder",
370+
Site: rbac.Permissions(map[string][]policy.Action{
371+
// May use template, read template-related info, & insert template-related resources (preset prebuilds).
372+
rbac.ResourceTemplate.Type: {policy.ActionRead, policy.ActionUpdate, policy.ActionUse},
373+
// May CRUD workspaces, and start/stop them.
374+
rbac.ResourceWorkspace.Type: {
375+
policy.ActionCreate, policy.ActionDelete, policy.ActionRead, policy.ActionUpdate,
376+
policy.ActionWorkspaceStart, policy.ActionWorkspaceStop,
377+
},
378+
}),
379+
},
380+
}),
381+
Scope: rbac.ScopeAll,
382+
}.WithCachedASTValue()
361383
)
362384

363385
// AsProvisionerd returns a context with an actor that has permissions required
@@ -412,6 +434,12 @@ func AsSystemReadProvisionerDaemons(ctx context.Context) context.Context {
412434
return context.WithValue(ctx, authContextKey{}, subjectSystemReadProvisionerDaemons)
413435
}
414436

437+
// AsPrebuildsOrchestrator returns a context with an actor that has permissions
438+
// to read orchestrator workspace prebuilds.
439+
func AsPrebuildsOrchestrator(ctx context.Context) context.Context {
440+
return context.WithValue(ctx, authContextKey{}, subjectPrebuildsOrchestrator)
441+
}
442+
415443
var AsRemoveActor = rbac.Subject{
416444
ID: "remove-actor",
417445
}
@@ -1106,6 +1134,15 @@ func (q *querier) BulkMarkNotificationMessagesSent(ctx context.Context, arg data
11061134
return q.db.BulkMarkNotificationMessagesSent(ctx, arg)
11071135
}
11081136

1137+
func (q *querier) ClaimPrebuild(ctx context.Context, newOwnerID database.ClaimPrebuildParams) (database.ClaimPrebuildRow, error) {
1138+
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceWorkspace); err != nil {
1139+
return database.ClaimPrebuildRow{
1140+
ID: uuid.Nil,
1141+
}, err
1142+
}
1143+
return q.db.ClaimPrebuild(ctx, newOwnerID)
1144+
}
1145+
11091146
func (q *querier) CleanTailnetCoordinators(ctx context.Context) error {
11101147
if err := q.authorizeContext(ctx, policy.ActionDelete, rbac.ResourceTailnetCoordinator); err != nil {
11111148
return err
@@ -2020,6 +2057,20 @@ func (q *querier) GetParameterSchemasByJobID(ctx context.Context, jobID uuid.UUI
20202057
return q.db.GetParameterSchemasByJobID(ctx, jobID)
20212058
}
20222059

2060+
func (q *querier) GetPrebuildMetrics(ctx context.Context) ([]database.GetPrebuildMetricsRow, error) {
2061+
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceTemplate); err != nil {
2062+
return nil, err
2063+
}
2064+
return q.db.GetPrebuildMetrics(ctx)
2065+
}
2066+
2067+
func (q *querier) GetPrebuildsInProgress(ctx context.Context) ([]database.GetPrebuildsInProgressRow, error) {
2068+
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceTemplate); err != nil {
2069+
return nil, err
2070+
}
2071+
return q.db.GetPrebuildsInProgress(ctx)
2072+
}
2073+
20232074
func (q *querier) GetPresetByWorkspaceBuildID(ctx context.Context, workspaceID uuid.UUID) (database.TemplateVersionPreset, error) {
20242075
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceTemplate); err != nil {
20252076
return database.TemplateVersionPreset{}, err
@@ -2037,6 +2088,13 @@ func (q *querier) GetPresetParametersByTemplateVersionID(ctx context.Context, te
20372088
return q.db.GetPresetParametersByTemplateVersionID(ctx, templateVersionID)
20382089
}
20392090

2091+
func (q *querier) GetPresetsBackoff(ctx context.Context, lookback time.Time) ([]database.GetPresetsBackoffRow, error) {
2092+
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceTemplate); err != nil {
2093+
return nil, err
2094+
}
2095+
return q.db.GetPresetsBackoff(ctx, lookback)
2096+
}
2097+
20402098
func (q *querier) GetPresetsByTemplateVersionID(ctx context.Context, templateVersionID uuid.UUID) ([]database.TemplateVersionPreset, error) {
20412099
// An actor can read template version presets if they can read the related template version.
20422100
_, err := q.GetTemplateVersionByID(ctx, templateVersionID)
@@ -2088,13 +2146,13 @@ func (q *querier) GetProvisionerJobByID(ctx context.Context, id uuid.UUID) (data
20882146
// can read the job.
20892147
_, err := q.GetWorkspaceBuildByJobID(ctx, id)
20902148
if err != nil {
2091-
return database.ProvisionerJob{}, err
2149+
return database.ProvisionerJob{}, xerrors.Errorf("fetch related workspace build: %w", err)
20922150
}
20932151
case database.ProvisionerJobTypeTemplateVersionDryRun, database.ProvisionerJobTypeTemplateVersionImport:
20942152
// Authorized call to get template version.
20952153
_, err := authorizedTemplateVersionFromJob(ctx, q, job)
20962154
if err != nil {
2097-
return database.ProvisionerJob{}, err
2155+
return database.ProvisionerJob{}, xerrors.Errorf("fetch related template version: %w", err)
20982156
}
20992157
default:
21002158
return database.ProvisionerJob{}, xerrors.Errorf("unknown job type: %q", job.Type)
@@ -2187,6 +2245,13 @@ func (q *querier) GetReplicasUpdatedAfter(ctx context.Context, updatedAt time.Ti
21872245
return q.db.GetReplicasUpdatedAfter(ctx, updatedAt)
21882246
}
21892247

2248+
func (q *querier) GetRunningPrebuilds(ctx context.Context) ([]database.GetRunningPrebuildsRow, error) {
2249+
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceTemplate); err != nil {
2250+
return nil, err
2251+
}
2252+
return q.db.GetRunningPrebuilds(ctx)
2253+
}
2254+
21902255
func (q *querier) GetRuntimeConfig(ctx context.Context, key string) (string, error) {
21912256
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceSystem); err != nil {
21922257
return "", err
@@ -2311,6 +2376,16 @@ func (q *querier) GetTemplateParameterInsights(ctx context.Context, arg database
23112376
return q.db.GetTemplateParameterInsights(ctx, arg)
23122377
}
23132378

2379+
func (q *querier) GetTemplatePresetsWithPrebuilds(ctx context.Context, templateID uuid.NullUUID) ([]database.GetTemplatePresetsWithPrebuildsRow, error) {
2380+
// Although this fetches presets. It filters them by prebuilds and is only of use to the prebuild system.
2381+
// As such, we authorize this in line with other prebuild queries, not with other preset queries.
2382+
2383+
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceTemplate); err != nil {
2384+
return nil, err
2385+
}
2386+
return q.db.GetTemplatePresetsWithPrebuilds(ctx, templateID)
2387+
}
2388+
23142389
func (q *querier) GetTemplateUsageStats(ctx context.Context, arg database.GetTemplateUsageStatsParams) ([]database.TemplateUsageStat, error) {
23152390
if err := q.authorizeTemplateInsights(ctx, arg.TemplateIDs); err != nil {
23162391
return nil, err
@@ -3235,6 +3310,13 @@ func (q *querier) InsertPresetParameters(ctx context.Context, arg database.Inser
32353310
return q.db.InsertPresetParameters(ctx, arg)
32363311
}
32373312

3313+
func (q *querier) InsertPresetPrebuild(ctx context.Context, arg database.InsertPresetPrebuildParams) (database.TemplateVersionPresetPrebuild, error) {
3314+
if err := q.authorizeContext(ctx, policy.ActionCreate, rbac.ResourceSystem); err != nil {
3315+
return database.TemplateVersionPresetPrebuild{}, err
3316+
}
3317+
return q.db.InsertPresetPrebuild(ctx, arg)
3318+
}
3319+
32383320
// TODO: We need to create a ProvisionerJob resource type
32393321
func (q *querier) InsertProvisionerJob(ctx context.Context, arg database.InsertProvisionerJobParams) (database.ProvisionerJob, error) {
32403322
// if err := q.authorizeContext(ctx, policy.ActionCreate, rbac.ResourceSystem); err != nil {

coderd/database/dbauthz/dbauthz_test.go

+61-2
Original file line numberDiff line numberDiff line change
@@ -979,8 +979,8 @@ func (s *MethodTestSuite) TestOrganization() {
979979
})
980980

981981
check.Args(database.OrganizationMembersParams{
982-
OrganizationID: uuid.UUID{},
983-
UserID: uuid.UUID{},
982+
OrganizationID: o.ID,
983+
UserID: u.ID,
984984
}).Asserts(
985985
mem, policy.ActionRead,
986986
)
@@ -4642,6 +4642,65 @@ func (s *MethodTestSuite) TestNotifications() {
46424642
}))
46434643
}
46444644

4645+
func (s *MethodTestSuite) TestPrebuilds() {
4646+
s.Run("ClaimPrebuild", s.Subtest(func(db database.Store, check *expects) {
4647+
check.Args(database.ClaimPrebuildParams{}).
4648+
Asserts(rbac.ResourceWorkspace, policy.ActionUpdate).
4649+
ErrorsWithInMemDB(dbmem.ErrUnimplemented).
4650+
ErrorsWithPG(sql.ErrNoRows)
4651+
}))
4652+
s.Run("GetPrebuildMetrics", s.Subtest(func(_ database.Store, check *expects) {
4653+
check.Args().
4654+
Asserts(rbac.ResourceTemplate, policy.ActionRead).
4655+
ErrorsWithInMemDB(dbmem.ErrUnimplemented)
4656+
}))
4657+
s.Run("GetPrebuildsInProgress", s.Subtest(func(_ database.Store, check *expects) {
4658+
check.Args().
4659+
Asserts(rbac.ResourceTemplate, policy.ActionRead).
4660+
ErrorsWithInMemDB(dbmem.ErrUnimplemented)
4661+
}))
4662+
s.Run("GetPresetsBackoff", s.Subtest(func(_ database.Store, check *expects) {
4663+
check.Args(time.Time{}).
4664+
Asserts(rbac.ResourceTemplate, policy.ActionRead).
4665+
ErrorsWithInMemDB(dbmem.ErrUnimplemented)
4666+
}))
4667+
s.Run("GetRunningPrebuilds", s.Subtest(func(_ database.Store, check *expects) {
4668+
check.Args().
4669+
Asserts(rbac.ResourceTemplate, policy.ActionRead).
4670+
ErrorsWithInMemDB(dbmem.ErrUnimplemented)
4671+
}))
4672+
s.Run("GetTemplatePresetsWithPrebuilds", s.Subtest(func(db database.Store, check *expects) {
4673+
user := dbgen.User(s.T(), db, database.User{})
4674+
check.Args(uuid.NullUUID{UUID: user.ID, Valid: true}).
4675+
Asserts(rbac.ResourceTemplate, policy.ActionRead).
4676+
ErrorsWithInMemDB(dbmem.ErrUnimplemented)
4677+
}))
4678+
s.Run("InsertPresetPrebuild", s.Subtest(func(db database.Store, check *expects) {
4679+
org := dbgen.Organization(s.T(), db, database.Organization{})
4680+
user := dbgen.User(s.T(), db, database.User{})
4681+
template := dbgen.Template(s.T(), db, database.Template{
4682+
CreatedBy: user.ID,
4683+
OrganizationID: org.ID,
4684+
})
4685+
templateVersion := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{
4686+
TemplateID: uuid.NullUUID{UUID: template.ID, Valid: true},
4687+
OrganizationID: org.ID,
4688+
CreatedBy: user.ID,
4689+
})
4690+
preset := dbgen.Preset(s.T(), db, database.InsertPresetParams{
4691+
Name: coderdtest.RandomName(s.T()),
4692+
TemplateVersionID: templateVersion.ID,
4693+
})
4694+
check.Args(database.InsertPresetPrebuildParams{
4695+
ID: uuid.New(),
4696+
PresetID: preset.ID,
4697+
DesiredInstances: 1,
4698+
}).
4699+
Asserts(rbac.ResourceSystem, policy.ActionCreate).
4700+
ErrorsWithInMemDB(dbmem.ErrUnimplemented)
4701+
}))
4702+
}
4703+
46454704
func (s *MethodTestSuite) TestOAuth2ProviderApps() {
46464705
s.Run("GetOAuth2ProviderApps", s.Subtest(func(db database.Store, check *expects) {
46474706
apps := []database.OAuth2ProviderApp{

coderd/database/dbgen/dbgen.go

+32
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,38 @@ func TelemetryItem(t testing.TB, db database.Store, seed database.TelemetryItem)
11581158
return item
11591159
}
11601160

1161+
func Preset(t testing.TB, db database.Store, seed database.InsertPresetParams) database.TemplateVersionPreset {
1162+
preset, err := db.InsertPreset(genCtx, database.InsertPresetParams{
1163+
TemplateVersionID: takeFirst(seed.TemplateVersionID, uuid.New()),
1164+
Name: takeFirst(seed.Name, testutil.GetRandomName(t)),
1165+
CreatedAt: takeFirst(seed.CreatedAt, dbtime.Now()),
1166+
})
1167+
require.NoError(t, err, "insert preset")
1168+
return preset
1169+
}
1170+
1171+
func PresetParameter(t testing.TB, db database.Store, seed database.InsertPresetParametersParams) []database.TemplateVersionPresetParameter {
1172+
parameters, err := db.InsertPresetParameters(genCtx, database.InsertPresetParametersParams{
1173+
TemplateVersionPresetID: takeFirst(seed.TemplateVersionPresetID, uuid.New()),
1174+
Names: takeFirstSlice(seed.Names, []string{testutil.GetRandomName(t)}),
1175+
Values: takeFirstSlice(seed.Values, []string{testutil.GetRandomName(t)}),
1176+
})
1177+
1178+
require.NoError(t, err, "insert preset parameters")
1179+
return parameters
1180+
}
1181+
1182+
func PresetPrebuild(t testing.TB, db database.Store, seed database.InsertPresetPrebuildParams) database.TemplateVersionPresetPrebuild {
1183+
prebuild, err := db.InsertPresetPrebuild(genCtx, database.InsertPresetPrebuildParams{
1184+
ID: takeFirst(seed.ID, uuid.New()),
1185+
PresetID: takeFirst(seed.PresetID, uuid.New()),
1186+
DesiredInstances: takeFirst(seed.DesiredInstances, 1),
1187+
InvalidateAfterSecs: 0,
1188+
})
1189+
require.NoError(t, err, "insert preset prebuild")
1190+
return prebuild
1191+
}
1192+
11611193
func provisionerJobTiming(t testing.TB, db database.Store, seed database.ProvisionerJobTiming) database.ProvisionerJobTiming {
11621194
timing, err := db.InsertProvisionerJobTimings(genCtx, database.InsertProvisionerJobTimingsParams{
11631195
JobID: takeFirst(seed.JobID, uuid.New()),

coderd/database/dbmem/dbmem.go

+33
Original file line numberDiff line numberDiff line change
@@ -1714,6 +1714,10 @@ func (*FakeQuerier) BulkMarkNotificationMessagesSent(_ context.Context, arg data
17141714
return int64(len(arg.IDs)), nil
17151715
}
17161716

1717+
func (*FakeQuerier) ClaimPrebuild(_ context.Context, _ database.ClaimPrebuildParams) (database.ClaimPrebuildRow, error) {
1718+
return database.ClaimPrebuildRow{}, ErrUnimplemented
1719+
}
1720+
17171721
func (*FakeQuerier) CleanTailnetCoordinators(_ context.Context) error {
17181722
return ErrUnimplemented
17191723
}
@@ -4023,6 +4027,14 @@ func (q *FakeQuerier) GetParameterSchemasByJobID(_ context.Context, jobID uuid.U
40234027
return parameters, nil
40244028
}
40254029

4030+
func (*FakeQuerier) GetPrebuildMetrics(_ context.Context) ([]database.GetPrebuildMetricsRow, error) {
4031+
return nil, ErrUnimplemented
4032+
}
4033+
4034+
func (*FakeQuerier) GetPrebuildsInProgress(_ context.Context) ([]database.GetPrebuildsInProgressRow, error) {
4035+
return nil, ErrUnimplemented
4036+
}
4037+
40264038
func (q *FakeQuerier) GetPresetByWorkspaceBuildID(_ context.Context, workspaceBuildID uuid.UUID) (database.TemplateVersionPreset, error) {
40274039
q.mutex.RLock()
40284040
defer q.mutex.RUnlock()
@@ -4065,6 +4077,10 @@ func (q *FakeQuerier) GetPresetParametersByTemplateVersionID(_ context.Context,
40654077
return parameters, nil
40664078
}
40674079

4080+
func (*FakeQuerier) GetPresetsBackoff(_ context.Context, _ time.Time) ([]database.GetPresetsBackoffRow, error) {
4081+
return nil, ErrUnimplemented
4082+
}
4083+
40684084
func (q *FakeQuerier) GetPresetsByTemplateVersionID(_ context.Context, templateVersionID uuid.UUID) ([]database.TemplateVersionPreset, error) {
40694085
q.mutex.RLock()
40704086
defer q.mutex.RUnlock()
@@ -4728,6 +4744,10 @@ func (q *FakeQuerier) GetReplicasUpdatedAfter(_ context.Context, updatedAt time.
47284744
return replicas, nil
47294745
}
47304746

4747+
func (*FakeQuerier) GetRunningPrebuilds(_ context.Context) ([]database.GetRunningPrebuildsRow, error) {
4748+
return nil, ErrUnimplemented
4749+
}
4750+
47314751
func (q *FakeQuerier) GetRuntimeConfig(_ context.Context, key string) (string, error) {
47324752
q.mutex.Lock()
47334753
defer q.mutex.Unlock()
@@ -5767,6 +5787,10 @@ func (q *FakeQuerier) GetTemplateParameterInsights(ctx context.Context, arg data
57675787
return rows, nil
57685788
}
57695789

5790+
func (*FakeQuerier) GetTemplatePresetsWithPrebuilds(_ context.Context, _ uuid.NullUUID) ([]database.GetTemplatePresetsWithPrebuildsRow, error) {
5791+
return nil, ErrUnimplemented
5792+
}
5793+
57705794
func (q *FakeQuerier) GetTemplateUsageStats(_ context.Context, arg database.GetTemplateUsageStatsParams) ([]database.TemplateUsageStat, error) {
57715795
err := validateDatabaseType(arg)
57725796
if err != nil {
@@ -8542,6 +8566,15 @@ func (q *FakeQuerier) InsertPresetParameters(_ context.Context, arg database.Ins
85428566
return presetParameters, nil
85438567
}
85448568

8569+
func (*FakeQuerier) InsertPresetPrebuild(_ context.Context, arg database.InsertPresetPrebuildParams) (database.TemplateVersionPresetPrebuild, error) {
8570+
err := validateDatabaseType(arg)
8571+
if err != nil {
8572+
return database.TemplateVersionPresetPrebuild{}, err
8573+
}
8574+
8575+
return database.TemplateVersionPresetPrebuild{}, ErrUnimplemented
8576+
}
8577+
85458578
func (q *FakeQuerier) InsertProvisionerJob(_ context.Context, arg database.InsertProvisionerJobParams) (database.ProvisionerJob, error) {
85468579
if err := validateDatabaseType(arg); err != nil {
85478580
return database.ProvisionerJob{}, err

0 commit comments

Comments
 (0)