Skip to content

Commit 69d13f1

Browse files
authored
chore: add archive column to template versions (#10178)
* chore: add archive column to template versions
1 parent c11f241 commit 69d13f1

15 files changed

+691
-18
lines changed

coderd/database/dbauthz/dbauthz.go

+27
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,17 @@ func (q *querier) AllUserIDs(ctx context.Context) ([]uuid.UUID, error) {
673673
return q.db.AllUserIDs(ctx)
674674
}
675675

676+
func (q *querier) ArchiveUnusedTemplateVersions(ctx context.Context, arg database.ArchiveUnusedTemplateVersionsParams) ([]uuid.UUID, error) {
677+
tpl, err := q.db.GetTemplateByID(ctx, arg.TemplateID)
678+
if err != nil {
679+
return nil, err
680+
}
681+
if err := q.authorizeContext(ctx, rbac.ActionUpdate, tpl); err != nil {
682+
return nil, err
683+
}
684+
return q.db.ArchiveUnusedTemplateVersions(ctx, arg)
685+
}
686+
676687
func (q *querier) CleanTailnetCoordinators(ctx context.Context) error {
677688
if err := q.authorizeContext(ctx, rbac.ActionDelete, rbac.ResourceTailnetCoordinator); err != nil {
678689
return err
@@ -2260,6 +2271,22 @@ func (q *querier) TryAcquireLock(ctx context.Context, id int64) (bool, error) {
22602271
return q.db.TryAcquireLock(ctx, id)
22612272
}
22622273

2274+
func (q *querier) UnarchiveTemplateVersion(ctx context.Context, arg database.UnarchiveTemplateVersionParams) error {
2275+
v, err := q.db.GetTemplateVersionByID(ctx, arg.TemplateVersionID)
2276+
if err != nil {
2277+
return err
2278+
}
2279+
2280+
tpl, err := q.db.GetTemplateByID(ctx, v.TemplateID.UUID)
2281+
if err != nil {
2282+
return err
2283+
}
2284+
if err := q.authorizeContext(ctx, rbac.ActionUpdate, tpl); err != nil {
2285+
return err
2286+
}
2287+
return q.db.UnarchiveTemplateVersion(ctx, arg)
2288+
}
2289+
22632290
func (q *querier) UpdateAPIKeyByID(ctx context.Context, arg database.UpdateAPIKeyByIDParams) error {
22642291
fetch := func(ctx context.Context, arg database.UpdateAPIKeyByIDParams) (database.APIKey, error) {
22652292
return q.db.GetAPIKeyByID(ctx, arg.ID)

coderd/database/dbauthz/dbauthz_test.go

+35
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,41 @@ func (s *MethodTestSuite) TestGroup() {
342342
}
343343

344344
func (s *MethodTestSuite) TestProvsionerJob() {
345+
s.Run("ArchiveUnusedTemplateVersions", s.Subtest(func(db database.Store, check *expects) {
346+
j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{
347+
Type: database.ProvisionerJobTypeTemplateVersionImport,
348+
Error: sql.NullString{
349+
String: "failed",
350+
Valid: true,
351+
},
352+
})
353+
tpl := dbgen.Template(s.T(), db, database.Template{})
354+
v := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{
355+
TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true},
356+
JobID: j.ID,
357+
})
358+
check.Args(database.ArchiveUnusedTemplateVersionsParams{
359+
UpdatedAt: dbtime.Now(),
360+
TemplateID: tpl.ID,
361+
TemplateVersionID: uuid.Nil,
362+
JobStatus: database.NullProvisionerJobStatus{},
363+
}).Asserts(v.RBACObject(tpl), rbac.ActionUpdate)
364+
}))
365+
s.Run("UnarchiveTemplateVersion", s.Subtest(func(db database.Store, check *expects) {
366+
j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{
367+
Type: database.ProvisionerJobTypeTemplateVersionImport,
368+
})
369+
tpl := dbgen.Template(s.T(), db, database.Template{})
370+
v := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{
371+
TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true},
372+
JobID: j.ID,
373+
Archived: true,
374+
})
375+
check.Args(database.UnarchiveTemplateVersionParams{
376+
UpdatedAt: dbtime.Now(),
377+
TemplateVersionID: v.ID,
378+
}).Asserts(v.RBACObject(tpl), rbac.ActionUpdate)
379+
}))
345380
s.Run("Build/GetProvisionerJobByID", s.Subtest(func(db database.Store, check *expects) {
346381
w := dbgen.Workspace(s.T(), db, database.Workspace{})
347382
j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{

coderd/database/dbfake/dbfake.go

+97
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,82 @@ func (q *FakeQuerier) AllUserIDs(_ context.Context) ([]uuid.UUID, error) {
846846
return userIDs, nil
847847
}
848848

849+
func (q *FakeQuerier) ArchiveUnusedTemplateVersions(_ context.Context, arg database.ArchiveUnusedTemplateVersionsParams) ([]uuid.UUID, error) {
850+
err := validateDatabaseType(arg)
851+
if err != nil {
852+
return nil, err
853+
}
854+
q.mutex.Lock()
855+
defer q.mutex.Unlock()
856+
type latestBuild struct {
857+
Number int32
858+
Version uuid.UUID
859+
}
860+
latest := make(map[uuid.UUID]latestBuild)
861+
862+
for _, b := range q.workspaceBuilds {
863+
v, ok := latest[b.WorkspaceID]
864+
if ok || b.BuildNumber < v.Number {
865+
// Not the latest
866+
continue
867+
}
868+
// Ignore deleted workspaces.
869+
if b.Transition == database.WorkspaceTransitionDelete {
870+
continue
871+
}
872+
latest[b.WorkspaceID] = latestBuild{
873+
Number: b.BuildNumber,
874+
Version: b.TemplateVersionID,
875+
}
876+
}
877+
878+
usedVersions := make(map[uuid.UUID]bool)
879+
for _, l := range latest {
880+
usedVersions[l.Version] = true
881+
}
882+
for _, tpl := range q.templates {
883+
usedVersions[tpl.ActiveVersionID] = true
884+
}
885+
886+
var archived []uuid.UUID
887+
for i, v := range q.templateVersions {
888+
if arg.TemplateVersionID != uuid.Nil {
889+
if v.ID != arg.TemplateVersionID {
890+
continue
891+
}
892+
}
893+
if v.Archived {
894+
continue
895+
}
896+
897+
if _, ok := usedVersions[v.ID]; !ok {
898+
var job *database.ProvisionerJob
899+
for i, j := range q.provisionerJobs {
900+
if v.JobID == j.ID {
901+
job = &q.provisionerJobs[i]
902+
break
903+
}
904+
}
905+
906+
if arg.JobStatus.Valid {
907+
if job.JobStatus != arg.JobStatus.ProvisionerJobStatus {
908+
continue
909+
}
910+
}
911+
912+
if job.JobStatus == database.ProvisionerJobStatusRunning || job.JobStatus == database.ProvisionerJobStatusPending {
913+
continue
914+
}
915+
916+
v.Archived = true
917+
q.templateVersions[i] = v
918+
archived = append(archived, v.ID)
919+
}
920+
}
921+
922+
return archived, nil
923+
}
924+
849925
func (*FakeQuerier) CleanTailnetCoordinators(_ context.Context) error {
850926
return ErrUnimplemented
851927
}
@@ -2759,6 +2835,9 @@ func (q *FakeQuerier) GetTemplateVersionsByTemplateID(_ context.Context, arg dat
27592835
if templateVersion.TemplateID.UUID != arg.TemplateID {
27602836
continue
27612837
}
2838+
if arg.Archived.Valid && arg.Archived.Bool != templateVersion.Archived {
2839+
continue
2840+
}
27622841
version = append(version, q.templateVersionWithUserNoLock(templateVersion))
27632842
}
27642843

@@ -5261,6 +5340,24 @@ func (*FakeQuerier) TryAcquireLock(_ context.Context, _ int64) (bool, error) {
52615340
return false, xerrors.New("TryAcquireLock must only be called within a transaction")
52625341
}
52635342

5343+
func (q *FakeQuerier) UnarchiveTemplateVersion(_ context.Context, arg database.UnarchiveTemplateVersionParams) error {
5344+
err := validateDatabaseType(arg)
5345+
if err != nil {
5346+
return err
5347+
}
5348+
5349+
for i, v := range q.data.templateVersions {
5350+
if v.ID == arg.TemplateVersionID {
5351+
v.Archived = false
5352+
v.UpdatedAt = arg.UpdatedAt
5353+
q.data.templateVersions[i] = v
5354+
return nil
5355+
}
5356+
}
5357+
5358+
return sql.ErrNoRows
5359+
}
5360+
52645361
func (q *FakeQuerier) UpdateAPIKeyByID(_ context.Context, arg database.UpdateAPIKeyByIDParams) error {
52655362
if err := validateDatabaseType(arg); err != nil {
52665363
return err

coderd/database/dbmetrics/dbmetrics.go

+14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/dbmock/dbmock.go

+29
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/dump.sql

+3-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
BEGIN;
2+
3+
-- The view will be rebuilt with the new column
4+
DROP VIEW template_version_with_user;
5+
6+
ALTER TABLE template_versions
7+
DROP COLUMN archived;
8+
9+
-- Restore the old version of the template_version_with_user view.
10+
CREATE VIEW
11+
template_version_with_user
12+
AS
13+
SELECT
14+
template_versions.*,
15+
coalesce(visible_users.avatar_url, '') AS created_by_avatar_url,
16+
coalesce(visible_users.username, '') AS created_by_username
17+
FROM
18+
template_versions
19+
LEFT JOIN
20+
visible_users
21+
ON
22+
template_versions.created_by = visible_users.id;
23+
24+
COMMENT ON VIEW template_version_with_user IS 'Joins in the username + avatar url of the created by user.';
25+
26+
COMMIT;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
BEGIN;
2+
3+
-- The view will be rebuilt with the new column
4+
DROP VIEW template_version_with_user;
5+
6+
-- Archived template versions are not visible or usable by default.
7+
ALTER TABLE template_versions
8+
ADD COLUMN archived BOOLEAN NOT NULL DEFAULT FALSE;
9+
10+
-- Restore the old version of the template_version_with_user view.
11+
CREATE VIEW
12+
template_version_with_user
13+
AS
14+
SELECT
15+
template_versions.*,
16+
coalesce(visible_users.avatar_url, '') AS created_by_avatar_url,
17+
coalesce(visible_users.username, '') AS created_by_username
18+
FROM
19+
template_versions
20+
LEFT JOIN
21+
visible_users
22+
ON
23+
template_versions.created_by = visible_users.id;
24+
25+
COMMENT ON VIEW template_version_with_user IS 'Joins in the username + avatar url of the created by user.';
26+
27+
COMMIT;

coderd/database/models.go

+3-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/querier.go

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)