From 4967b6bb648a9a72f883b0e9f102162ba58ab012 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 16 Oct 2024 16:32:11 -0500 Subject: [PATCH 01/23] chore: new workspace view to join in owner, template, and org Previously this data was fetched via seperate queries. This caused an issue in orgs, as users are site wide scoped. So user read access was required to read another user's username. Now it is all joined into the workspace, implcitly giving read perms to some fields in related objects. --- coderd/activitybump_test.go | 2 +- coderd/agentapi/api.go | 6 +- coderd/agentapi/stats.go | 2 +- coderd/audit/diff.go | 2 +- coderd/autobuild/lifecycle_executor.go | 19 +- coderd/database/dbauthz/dbauthz.go | 28 ++- coderd/database/dbmem/dbmem.go | 161 +++++++----- coderd/database/dbmetrics/dbmetrics.go | 12 +- coderd/database/dbmock/dbmock.go | 24 +- coderd/database/dump.sql | 33 +++ .../000262_workspace_with_names.down.sql | 0 .../000262_workspace_with_names.up.sql | 33 +++ coderd/database/modelmethods.go | 32 ++- coderd/database/modelqueries.go | 10 +- coderd/database/modelqueries_internal_test.go | 74 ++++++ coderd/database/models.go | 63 +++-- coderd/database/querier.go | 14 +- coderd/database/querier_test.go | 8 +- coderd/database/queries.sql.go | 235 +++++++++++------- coderd/database/queries/workspaces.sql | 17 +- coderd/database/sqlc.yaml | 2 + coderd/httpmw/workspaceagent.go | 10 +- coderd/prometheusmetrics/prometheusmetrics.go | 2 +- coderd/util/slice/slice.go | 11 + coderd/workspaceagents.go | 3 +- coderd/workspacebuilds.go | 70 +----- coderd/workspaces.go | 178 +++++-------- 27 files changed, 625 insertions(+), 426 deletions(-) create mode 100644 coderd/database/migrations/000262_workspace_with_names.down.sql create mode 100644 coderd/database/migrations/000262_workspace_with_names.up.sql diff --git a/coderd/activitybump_test.go b/coderd/activitybump_test.go index 60aec23475885..aa0ad925c2357 100644 --- a/coderd/activitybump_test.go +++ b/coderd/activitybump_test.go @@ -199,7 +199,7 @@ func TestWorkspaceActivityBump(t *testing.T) { t.Parallel() client, workspace, assertBumped := setupActivityTest(t) - + Access - Control - Allow - Origin resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) conn, err := workspacesdk.New(client). DialAgent(ctx, resources[0].Agents[0].ID, &workspacesdk.DialAgentOptions{ diff --git a/coderd/agentapi/api.go b/coderd/agentapi/api.go index bea1fa5d881a3..f69f366b43d4e 100644 --- a/coderd/agentapi/api.go +++ b/coderd/agentapi/api.go @@ -106,7 +106,7 @@ func New(opts Options) *API { if err != nil { return uuid.Nil, err } - return ws.Workspace.ID, nil + return ws.ID, nil }, } @@ -231,9 +231,9 @@ func (a *API) workspaceID(ctx context.Context, agent *database.WorkspaceAgent) ( } a.mu.Lock() - a.cachedWorkspaceID = getWorkspaceAgentByIDRow.Workspace.ID + a.cachedWorkspaceID = getWorkspaceAgentByIDRow.ID a.mu.Unlock() - return getWorkspaceAgentByIDRow.Workspace.ID, nil + return getWorkspaceAgentByIDRow.ID, nil } func (a *API) publishWorkspaceUpdate(ctx context.Context, agent *database.WorkspaceAgent) error { diff --git a/coderd/agentapi/stats.go b/coderd/agentapi/stats.go index 226f06732d4ee..3108d17f75b14 100644 --- a/coderd/agentapi/stats.go +++ b/coderd/agentapi/stats.go @@ -50,7 +50,7 @@ func (a *StatsAPI) UpdateStats(ctx context.Context, req *agentproto.UpdateStatsR if err != nil { return nil, xerrors.Errorf("get workspace by agent ID %q: %w", workspaceAgent.ID, err) } - workspace := getWorkspaceAgentByIDRow.Workspace + workspace := getWorkspaceAgentByIDRow a.Log.Debug(ctx, "read stats report", slog.F("interval", a.AgentStatsRefreshInterval), slog.F("workspace_id", workspace.ID), diff --git a/coderd/audit/diff.go b/coderd/audit/diff.go index 04943c760a55e..8d5923d575054 100644 --- a/coderd/audit/diff.go +++ b/coderd/audit/diff.go @@ -12,7 +12,7 @@ type Auditable interface { database.Template | database.TemplateVersion | database.User | - database.Workspace | + database.WorkspaceTable | database.GitSSHKey | database.WorkspaceBuild | database.AuditableGroup | diff --git a/coderd/autobuild/lifecycle_executor.go b/coderd/autobuild/lifecycle_executor.go index 5bd8efe2b9fcf..b83d0522d4f9f 100644 --- a/coderd/autobuild/lifecycle_executor.go +++ b/coderd/autobuild/lifecycle_executor.go @@ -234,7 +234,7 @@ func (e *Executor) runOnce(t time.Time) Stats { // threshold for inactivity. if reason == database.BuildReasonDormancy { wsOld := ws - ws, err = tx.UpdateWorkspaceDormantDeletingAt(e.ctx, database.UpdateWorkspaceDormantDeletingAtParams{ + wsNew, err := tx.UpdateWorkspaceDormantDeletingAt(e.ctx, database.UpdateWorkspaceDormantDeletingAtParams{ ID: ws.ID, DormantAt: sql.NullTime{ Time: dbtime.Now(), @@ -242,14 +242,17 @@ func (e *Executor) runOnce(t time.Time) Stats { }, }) - auditLog = &auditParams{ - Old: wsOld, - New: ws, - } if err != nil { return xerrors.Errorf("update workspace dormant deleting at: %w", err) } + auditLog = &auditParams{ + Old: wsOld.WorkspaceTable(), + New: wsNew, + } + // To keep the `ws` accurate without doing a sql fetch + ws.DormantAt = wsNew.DormantAt + shouldNotifyDormancy = true log.Info(e.ctx, "dormant workspace", @@ -510,8 +513,8 @@ func isEligibleForFailedStop(build database.WorkspaceBuild, job database.Provisi } type auditParams struct { - Old database.Workspace - New database.Workspace + Old database.WorkspaceTable + New database.WorkspaceTable Success bool } @@ -521,7 +524,7 @@ func auditBuild(ctx context.Context, log slog.Logger, auditor audit.Auditor, par status = http.StatusOK } - audit.BackgroundAudit(ctx, &audit.BackgroundAuditParams[database.Workspace]{ + audit.BackgroundAudit(ctx, &audit.BackgroundAuditParams[database.WorkspaceTable]{ Audit: auditor, Log: log, UserID: params.New.OwnerID, diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index a587788791c35..052f25450e6a5 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -2574,7 +2574,7 @@ func (q *querier) GetWorkspaceBuildsCreatedAfter(ctx context.Context, createdAt return q.db.GetWorkspaceBuildsCreatedAfter(ctx, createdAt) } -func (q *querier) GetWorkspaceByAgentID(ctx context.Context, agentID uuid.UUID) (database.GetWorkspaceByAgentIDRow, error) { +func (q *querier) GetWorkspaceByAgentID(ctx context.Context, agentID uuid.UUID) (database.Workspace, error) { return fetch(q.log, q.auth, q.db.GetWorkspaceByAgentID)(ctx, agentID) } @@ -2719,7 +2719,7 @@ func (q *querier) GetWorkspaces(ctx context.Context, arg database.GetWorkspacesP return q.db.GetAuthorizedWorkspaces(ctx, arg, prep) } -func (q *querier) GetWorkspacesEligibleForTransition(ctx context.Context, now time.Time) ([]database.Workspace, error) { +func (q *querier) GetWorkspacesEligibleForTransition(ctx context.Context, now time.Time) ([]database.WorkspaceTable, error) { return q.db.GetWorkspacesEligibleForTransition(ctx, now) } @@ -3009,7 +3009,7 @@ func (q *querier) InsertUserLink(ctx context.Context, arg database.InsertUserLin return q.db.InsertUserLink(ctx, arg) } -func (q *querier) InsertWorkspace(ctx context.Context, arg database.InsertWorkspaceParams) (database.Workspace, error) { +func (q *querier) InsertWorkspace(ctx context.Context, arg database.InsertWorkspaceParams) (database.WorkspaceTable, error) { obj := rbac.ResourceWorkspace.WithOwner(arg.OwnerID.String()).InOrg(arg.OrganizationID) return insert(q.log, q.auth, obj, q.db.InsertWorkspace)(ctx, arg) } @@ -3751,9 +3751,13 @@ func (q *querier) UpdateUserStatus(ctx context.Context, arg database.UpdateUserS return updateWithReturn(q.log, q.auth, fetch, q.db.UpdateUserStatus)(ctx, arg) } -func (q *querier) UpdateWorkspace(ctx context.Context, arg database.UpdateWorkspaceParams) (database.Workspace, error) { - fetch := func(ctx context.Context, arg database.UpdateWorkspaceParams) (database.Workspace, error) { - return q.db.GetWorkspaceByID(ctx, arg.ID) +func (q *querier) UpdateWorkspace(ctx context.Context, arg database.UpdateWorkspaceParams) (database.WorkspaceTable, error) { + fetch := func(ctx context.Context, arg database.UpdateWorkspaceParams) (database.WorkspaceTable, error) { + w, err := q.db.GetWorkspaceByID(ctx, arg.ID) + if err != nil { + return database.WorkspaceTable{}, err + } + return w.WorkspaceTable(), nil } return updateWithReturn(q.log, q.auth, fetch, q.db.UpdateWorkspace)(ctx, arg) } @@ -3905,9 +3909,13 @@ func (q *querier) UpdateWorkspaceDeletedByID(ctx context.Context, arg database.U return deleteQ(q.log, q.auth, fetch, q.db.UpdateWorkspaceDeletedByID)(ctx, arg) } -func (q *querier) UpdateWorkspaceDormantDeletingAt(ctx context.Context, arg database.UpdateWorkspaceDormantDeletingAtParams) (database.Workspace, error) { - fetch := func(ctx context.Context, arg database.UpdateWorkspaceDormantDeletingAtParams) (database.Workspace, error) { - return q.db.GetWorkspaceByID(ctx, arg.ID) +func (q *querier) UpdateWorkspaceDormantDeletingAt(ctx context.Context, arg database.UpdateWorkspaceDormantDeletingAtParams) (database.WorkspaceTable, error) { + fetch := func(ctx context.Context, arg database.UpdateWorkspaceDormantDeletingAtParams) (database.WorkspaceTable, error) { + w, err := q.db.GetWorkspaceByID(ctx, arg.ID) + if err != nil { + return database.WorkspaceTable{}, err + } + return w.WorkspaceTable(), nil } return updateWithReturn(q.log, q.auth, fetch, q.db.UpdateWorkspaceDormantDeletingAt)(ctx, arg) } @@ -3940,7 +3948,7 @@ func (q *querier) UpdateWorkspaceTTL(ctx context.Context, arg database.UpdateWor return update(q.log, q.auth, fetch, q.db.UpdateWorkspaceTTL)(ctx, arg) } -func (q *querier) UpdateWorkspacesDormantDeletingAtByTemplateID(ctx context.Context, arg database.UpdateWorkspacesDormantDeletingAtByTemplateIDParams) ([]database.Workspace, error) { +func (q *querier) UpdateWorkspacesDormantDeletingAtByTemplateID(ctx context.Context, arg database.UpdateWorkspacesDormantDeletingAtByTemplateIDParams) ([]database.WorkspaceTable, error) { template, err := q.db.GetTemplateByID(ctx, arg.TemplateID) if err != nil { return nil, xerrors.Errorf("get template by id: %w", err) diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index ef7a2e63f0b5f..2e2b712055b1d 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -81,7 +81,7 @@ func New() database.Store { workspaceAgentLogs: make([]database.WorkspaceAgentLog, 0), workspaceBuilds: make([]database.WorkspaceBuild, 0), workspaceApps: make([]database.WorkspaceApp, 0), - workspaces: make([]database.Workspace, 0), + workspaces: make([]database.WorkspaceTable, 0), licenses: make([]database.License, 0), workspaceProxies: make([]database.WorkspaceProxy, 0), customRoles: make([]database.CustomRole, 0), @@ -232,7 +232,7 @@ type data struct { workspaceBuildParameters []database.WorkspaceBuildParameter workspaceResourceMetadata []database.WorkspaceResourceMetadatum workspaceResources []database.WorkspaceResource - workspaces []database.Workspace + workspaces []database.WorkspaceTable workspaceProxies []database.WorkspaceProxy customRoles []database.CustomRole provisionerJobTimings []database.ProvisionerJobTiming @@ -445,9 +445,11 @@ func mapAgentStatus(dbAgent database.WorkspaceAgent, agentInactiveDisconnectTime return status } -func (q *FakeQuerier) convertToWorkspaceRowsNoLock(ctx context.Context, workspaces []database.Workspace, count int64, withSummary bool) []database.GetWorkspacesRow { //nolint:revive // withSummary flag ensures the extra technical row +func (q *FakeQuerier) convertToWorkspaceRowsNoLock(ctx context.Context, workspaces []database.WorkspaceTable, count int64, withSummary bool) []database.GetWorkspacesRow { //nolint:revive // withSummary flag ensures the extra technical row rows := make([]database.GetWorkspacesRow, 0, len(workspaces)) for _, w := range workspaces { + extended := q.extendWorkspace(w) + wr := database.GetWorkspacesRow{ ID: w.ID, CreatedAt: w.CreatedAt, @@ -462,16 +464,33 @@ func (q *FakeQuerier) convertToWorkspaceRowsNoLock(ctx context.Context, workspac LastUsedAt: w.LastUsedAt, DormantAt: w.DormantAt, DeletingAt: w.DeletingAt, - Count: count, AutomaticUpdates: w.AutomaticUpdates, Favorite: w.Favorite, - } - for _, t := range q.templates { - if t.ID == w.TemplateID { - wr.TemplateName = t.Name - break - } + OwnerAvatarUrl: extended.OwnerAvatarUrl, + OwnerUsername: extended.OwnerUsername, + + OrganizationName: extended.OrganizationName, + OrganizationDisplayName: extended.OrganizationDisplayName, + OrganizationIcon: extended.OrganizationIcon, + OrganizationDescription: extended.OrganizationDescription, + + TemplateName: extended.TemplateName, + TemplateDisplayName: extended.TemplateDisplayName, + TemplateIcon: extended.TemplateIcon, + TemplateDescription: extended.TemplateDescription, + + Count: count, + + // These fields are missing! + // Try to resolve them below + TemplateVersionID: uuid.UUID{}, + TemplateVersionName: sql.NullString{}, + LatestBuildCompletedAt: sql.NullTime{}, + LatestBuildCanceledAt: sql.NullTime{}, + LatestBuildError: sql.NullString{}, + LatestBuildTransition: "", + LatestBuildStatus: "", } if build, err := q.getLatestWorkspaceBuildByWorkspaceIDNoLock(ctx, w.ID); err == nil { @@ -488,15 +507,14 @@ func (q *FakeQuerier) convertToWorkspaceRowsNoLock(ctx context.Context, workspac if pj, err := q.getProvisionerJobByIDNoLock(ctx, build.JobID); err == nil { wr.LatestBuildStatus = pj.JobStatus + wr.LatestBuildCanceledAt = pj.CanceledAt + wr.LatestBuildCompletedAt = pj.CompletedAt + wr.LatestBuildError = pj.Error } wr.LatestBuildTransition = build.Transition } - if u, err := q.getUserByIDNoLock(w.OwnerID); err == nil { - wr.Username = u.Username - } - rows = append(rows, wr) } if withSummary { @@ -509,14 +527,49 @@ func (q *FakeQuerier) convertToWorkspaceRowsNoLock(ctx context.Context, workspac } func (q *FakeQuerier) getWorkspaceByIDNoLock(_ context.Context, id uuid.UUID) (database.Workspace, error) { - for _, workspace := range q.workspaces { - if workspace.ID == id { - return workspace, nil - } + return q.getWorkspaceNoLock(func(w database.WorkspaceTable) bool { + return w.ID == id + }) +} + +func (q *FakeQuerier) getWorkspaceNoLock(find func(w database.WorkspaceTable) bool) (database.Workspace, error) { + w, found := slice.Find(q.workspaces, find) + if found { + return q.extendWorkspace(w), nil } return database.Workspace{}, sql.ErrNoRows } +func (q *FakeQuerier) extendWorkspace(w database.WorkspaceTable) database.Workspace { + var extended database.Workspace + // This is a cheeky way to copy the fields over without explicitly listing them all. + d, _ := json.Marshal(w) + _ = json.Unmarshal(d, &extended) + + org, _ := slice.Find(q.organizations, func(o database.Organization) bool { + return o.ID == w.OrganizationID + }) + extended.OrganizationDescription = org.Description + extended.OrganizationDisplayName = org.DisplayName + extended.OrganizationIcon = org.Icon + + tpl, _ := slice.Find(q.templates, func(t database.TemplateTable) bool { + return t.ID == w.TemplateID + }) + extended.TemplateName = tpl.Name + extended.TemplateDisplayName = tpl.DisplayName + extended.TemplateDescription = tpl.Description + extended.TemplateIcon = tpl.Icon + + owner, _ := slice.Find(q.users, func(u database.User) bool { + return u.ID == w.OwnerID + }) + extended.OwnerUsername = owner.Username + extended.OwnerAvatarUrl = owner.AvatarURL + + return extended +} + func (q *FakeQuerier) getWorkspaceByAgentIDNoLock(_ context.Context, agentID uuid.UUID) (database.Workspace, error) { var agent database.WorkspaceAgent for _, _agent := range q.workspaceAgents { @@ -551,13 +604,9 @@ func (q *FakeQuerier) getWorkspaceByAgentIDNoLock(_ context.Context, agentID uui return database.Workspace{}, sql.ErrNoRows } - for _, workspace := range q.workspaces { - if workspace.ID == build.WorkspaceID { - return workspace, nil - } - } - - return database.Workspace{}, sql.ErrNoRows + return q.getWorkspaceNoLock(func(w database.WorkspaceTable) bool { + return w.ID == build.WorkspaceID + }) } func (q *FakeQuerier) getWorkspaceBuildByIDNoLock(_ context.Context, id uuid.UUID) (database.WorkspaceBuild, error) { @@ -986,14 +1035,14 @@ func (q *FakeQuerier) getLatestWorkspaceAppByTemplateIDUserIDSlugNoLock(ctx cont LIMIT 1 */ - var workspaces []database.Workspace + var workspaces []database.WorkspaceTable for _, w := range q.workspaces { if w.TemplateID != templateID || w.OwnerID != userID { continue } workspaces = append(workspaces, w) } - slices.SortFunc(workspaces, func(a, b database.Workspace) int { + slices.SortFunc(workspaces, func(a, b database.WorkspaceTable) int { if a.CreatedAt.Before(b.CreatedAt) { return 1 } else if a.CreatedAt.Equal(b.CreatedAt) { @@ -5644,7 +5693,7 @@ func (q *FakeQuerier) GetWorkspaceAgentAndLatestBuildByAuthToken(_ context.Conte continue } row := database.GetWorkspaceAgentAndLatestBuildByAuthTokenRow{ - Workspace: database.Workspace{ + WorkspaceTable: database.WorkspaceTable{ ID: ws.ID, TemplateID: ws.TemplateID, }, @@ -5655,7 +5704,7 @@ func (q *FakeQuerier) GetWorkspaceAgentAndLatestBuildByAuthToken(_ context.Conte if err != nil { return database.GetWorkspaceAgentAndLatestBuildByAuthTokenRow{}, sql.ErrNoRows } - row.Workspace.OwnerID = usr.ID + row.WorkspaceTable.OwnerID = usr.ID // Keep track of the latest build number rows = append(rows, row) @@ -5672,7 +5721,7 @@ func (q *FakeQuerier) GetWorkspaceAgentAndLatestBuildByAuthToken(_ context.Conte continue } - if rows[i].WorkspaceBuild.BuildNumber != latestBuildNumber[rows[i].Workspace.ID] { + if rows[i].WorkspaceBuild.BuildNumber != latestBuildNumber[rows[i].WorkspaceTable.ID] { continue } @@ -6514,24 +6563,16 @@ func (q *FakeQuerier) GetWorkspaceBuildsCreatedAfter(_ context.Context, after ti return workspaceBuilds, nil } -func (q *FakeQuerier) GetWorkspaceByAgentID(ctx context.Context, agentID uuid.UUID) (database.GetWorkspaceByAgentIDRow, error) { +func (q *FakeQuerier) GetWorkspaceByAgentID(ctx context.Context, agentID uuid.UUID) (database.Workspace, error) { q.mutex.RLock() defer q.mutex.RUnlock() w, err := q.getWorkspaceByAgentIDNoLock(ctx, agentID) if err != nil { - return database.GetWorkspaceByAgentIDRow{}, err - } - - tpl, err := q.getTemplateByIDNoLock(ctx, w.TemplateID) - if err != nil { - return database.GetWorkspaceByAgentIDRow{}, err + return database.Workspace{}, err } - return database.GetWorkspaceByAgentIDRow{ - Workspace: w, - TemplateName: tpl.Name, - }, nil + return w, nil } func (q *FakeQuerier) GetWorkspaceByID(ctx context.Context, id uuid.UUID) (database.Workspace, error) { @@ -6549,7 +6590,7 @@ func (q *FakeQuerier) GetWorkspaceByOwnerIDAndName(_ context.Context, arg databa q.mutex.RLock() defer q.mutex.RUnlock() - var found *database.Workspace + var found *database.WorkspaceTable for _, workspace := range q.workspaces { workspace := workspace if workspace.OwnerID != arg.OwnerID { @@ -6568,7 +6609,7 @@ func (q *FakeQuerier) GetWorkspaceByOwnerIDAndName(_ context.Context, arg databa } } if found != nil { - return *found, nil + return q.extendWorkspace(*found), nil } return database.Workspace{}, sql.ErrNoRows } @@ -6794,11 +6835,11 @@ func (q *FakeQuerier) GetWorkspaces(ctx context.Context, arg database.GetWorkspa return workspaceRows, err } -func (q *FakeQuerier) GetWorkspacesEligibleForTransition(ctx context.Context, now time.Time) ([]database.Workspace, error) { +func (q *FakeQuerier) GetWorkspacesEligibleForTransition(ctx context.Context, now time.Time) ([]database.WorkspaceTable, error) { q.mutex.RLock() defer q.mutex.RUnlock() - workspaces := []database.Workspace{} + workspaces := []database.WorkspaceTable{} for _, workspace := range q.workspaces { build, err := q.getLatestWorkspaceBuildByWorkspaceIDNoLock(ctx, workspace.ID) if err != nil { @@ -7759,16 +7800,16 @@ func (q *FakeQuerier) InsertUserLink(_ context.Context, args database.InsertUser return link, nil } -func (q *FakeQuerier) InsertWorkspace(_ context.Context, arg database.InsertWorkspaceParams) (database.Workspace, error) { +func (q *FakeQuerier) InsertWorkspace(_ context.Context, arg database.InsertWorkspaceParams) (database.WorkspaceTable, error) { if err := validateDatabaseType(arg); err != nil { - return database.Workspace{}, err + return database.WorkspaceTable{}, err } q.mutex.Lock() defer q.mutex.Unlock() //nolint:gosimple - workspace := database.Workspace{ + workspace := database.WorkspaceTable{ ID: arg.ID, CreatedAt: arg.CreatedAt, UpdatedAt: arg.UpdatedAt, @@ -9408,9 +9449,9 @@ func (q *FakeQuerier) UpdateUserStatus(_ context.Context, arg database.UpdateUse return database.User{}, sql.ErrNoRows } -func (q *FakeQuerier) UpdateWorkspace(_ context.Context, arg database.UpdateWorkspaceParams) (database.Workspace, error) { +func (q *FakeQuerier) UpdateWorkspace(_ context.Context, arg database.UpdateWorkspaceParams) (database.WorkspaceTable, error) { if err := validateDatabaseType(arg); err != nil { - return database.Workspace{}, err + return database.WorkspaceTable{}, err } q.mutex.Lock() @@ -9425,7 +9466,7 @@ func (q *FakeQuerier) UpdateWorkspace(_ context.Context, arg database.UpdateWork continue } if other.Name == arg.Name { - return database.Workspace{}, errUniqueConstraint + return database.WorkspaceTable{}, errUniqueConstraint } } @@ -9435,7 +9476,7 @@ func (q *FakeQuerier) UpdateWorkspace(_ context.Context, arg database.UpdateWork return workspace, nil } - return database.Workspace{}, sql.ErrNoRows + return database.WorkspaceTable{}, sql.ErrNoRows } func (q *FakeQuerier) UpdateWorkspaceAgentConnectionByID(_ context.Context, arg database.UpdateWorkspaceAgentConnectionByIDParams) error { @@ -9700,9 +9741,9 @@ func (q *FakeQuerier) UpdateWorkspaceDeletedByID(_ context.Context, arg database return sql.ErrNoRows } -func (q *FakeQuerier) UpdateWorkspaceDormantDeletingAt(_ context.Context, arg database.UpdateWorkspaceDormantDeletingAtParams) (database.Workspace, error) { +func (q *FakeQuerier) UpdateWorkspaceDormantDeletingAt(_ context.Context, arg database.UpdateWorkspaceDormantDeletingAtParams) (database.WorkspaceTable, error) { if err := validateDatabaseType(arg); err != nil { - return database.Workspace{}, err + return database.WorkspaceTable{}, err } q.mutex.Lock() defer q.mutex.Unlock() @@ -9724,7 +9765,7 @@ func (q *FakeQuerier) UpdateWorkspaceDormantDeletingAt(_ context.Context, arg da } } if template.ID == uuid.Nil { - return database.Workspace{}, xerrors.Errorf("unable to find workspace template") + return database.WorkspaceTable{}, xerrors.Errorf("unable to find workspace template") } if template.TimeTilDormantAutoDelete > 0 { workspace.DeletingAt = sql.NullTime{ @@ -9736,7 +9777,7 @@ func (q *FakeQuerier) UpdateWorkspaceDormantDeletingAt(_ context.Context, arg da q.workspaces[index] = workspace return workspace, nil } - return database.Workspace{}, sql.ErrNoRows + return database.WorkspaceTable{}, sql.ErrNoRows } func (q *FakeQuerier) UpdateWorkspaceLastUsedAt(_ context.Context, arg database.UpdateWorkspaceLastUsedAtParams) error { @@ -9819,7 +9860,7 @@ func (q *FakeQuerier) UpdateWorkspaceTTL(_ context.Context, arg database.UpdateW return sql.ErrNoRows } -func (q *FakeQuerier) UpdateWorkspacesDormantDeletingAtByTemplateID(_ context.Context, arg database.UpdateWorkspacesDormantDeletingAtByTemplateIDParams) ([]database.Workspace, error) { +func (q *FakeQuerier) UpdateWorkspacesDormantDeletingAtByTemplateID(_ context.Context, arg database.UpdateWorkspacesDormantDeletingAtByTemplateIDParams) ([]database.WorkspaceTable, error) { q.mutex.Lock() defer q.mutex.Unlock() @@ -9828,7 +9869,7 @@ func (q *FakeQuerier) UpdateWorkspacesDormantDeletingAtByTemplateID(_ context.Co return nil, err } - affectedRows := []database.Workspace{} + affectedRows := []database.WorkspaceTable{} for i, ws := range q.workspaces { if ws.TemplateID != arg.TemplateID { continue @@ -10863,7 +10904,7 @@ func (q *FakeQuerier) GetAuthorizedWorkspaces(ctx context.Context, arg database. } } - workspaces := make([]database.Workspace, 0) + workspaces := make([]database.WorkspaceTable, 0) for _, workspace := range q.workspaces { if arg.OwnerID != uuid.Nil && workspace.OwnerID != arg.OwnerID { continue @@ -11159,7 +11200,7 @@ func (q *FakeQuerier) GetAuthorizedWorkspaces(ctx context.Context, arg database. if arg.Offset > 0 { if int(arg.Offset) > len(workspaces) { - return q.convertToWorkspaceRowsNoLock(ctx, []database.Workspace{}, int64(beforePageCount), arg.WithSummary), nil + return q.convertToWorkspaceRowsNoLock(ctx, []database.WorkspaceTable{}, int64(beforePageCount), arg.WithSummary), nil } workspaces = workspaces[arg.Offset:] } diff --git a/coderd/database/dbmetrics/dbmetrics.go b/coderd/database/dbmetrics/dbmetrics.go index b543d27c5f833..c3e9de22fb0d8 100644 --- a/coderd/database/dbmetrics/dbmetrics.go +++ b/coderd/database/dbmetrics/dbmetrics.go @@ -1544,7 +1544,7 @@ func (m metricsStore) GetWorkspaceBuildsCreatedAfter(ctx context.Context, create return builds, err } -func (m metricsStore) GetWorkspaceByAgentID(ctx context.Context, agentID uuid.UUID) (database.GetWorkspaceByAgentIDRow, error) { +func (m metricsStore) GetWorkspaceByAgentID(ctx context.Context, agentID uuid.UUID) (database.Workspace, error) { start := time.Now() workspace, err := m.s.GetWorkspaceByAgentID(ctx, agentID) m.queryLatencies.WithLabelValues("GetWorkspaceByAgentID").Observe(time.Since(start).Seconds()) @@ -1656,7 +1656,7 @@ func (m metricsStore) GetWorkspaces(ctx context.Context, arg database.GetWorkspa return workspaces, err } -func (m metricsStore) GetWorkspacesEligibleForTransition(ctx context.Context, now time.Time) ([]database.Workspace, error) { +func (m metricsStore) GetWorkspacesEligibleForTransition(ctx context.Context, now time.Time) ([]database.WorkspaceTable, error) { start := time.Now() workspaces, err := m.s.GetWorkspacesEligibleForTransition(ctx, now) m.queryLatencies.WithLabelValues("GetWorkspacesEligibleForAutoStartStop").Observe(time.Since(start).Seconds()) @@ -1908,7 +1908,7 @@ func (m metricsStore) InsertUserLink(ctx context.Context, arg database.InsertUse return link, err } -func (m metricsStore) InsertWorkspace(ctx context.Context, arg database.InsertWorkspaceParams) (database.Workspace, error) { +func (m metricsStore) InsertWorkspace(ctx context.Context, arg database.InsertWorkspaceParams) (database.WorkspaceTable, error) { start := time.Now() workspace, err := m.s.InsertWorkspace(ctx, arg) m.queryLatencies.WithLabelValues("InsertWorkspace").Observe(time.Since(start).Seconds()) @@ -2391,7 +2391,7 @@ func (m metricsStore) UpdateUserStatus(ctx context.Context, arg database.UpdateU return user, err } -func (m metricsStore) UpdateWorkspace(ctx context.Context, arg database.UpdateWorkspaceParams) (database.Workspace, error) { +func (m metricsStore) UpdateWorkspace(ctx context.Context, arg database.UpdateWorkspaceParams) (database.WorkspaceTable, error) { start := time.Now() workspace, err := m.s.UpdateWorkspace(ctx, arg) m.queryLatencies.WithLabelValues("UpdateWorkspace").Observe(time.Since(start).Seconds()) @@ -2482,7 +2482,7 @@ func (m metricsStore) UpdateWorkspaceDeletedByID(ctx context.Context, arg databa return err } -func (m metricsStore) UpdateWorkspaceDormantDeletingAt(ctx context.Context, arg database.UpdateWorkspaceDormantDeletingAtParams) (database.Workspace, error) { +func (m metricsStore) UpdateWorkspaceDormantDeletingAt(ctx context.Context, arg database.UpdateWorkspaceDormantDeletingAtParams) (database.WorkspaceTable, error) { start := time.Now() ws, r0 := m.s.UpdateWorkspaceDormantDeletingAt(ctx, arg) m.queryLatencies.WithLabelValues("UpdateWorkspaceDormantDeletingAt").Observe(time.Since(start).Seconds()) @@ -2517,7 +2517,7 @@ func (m metricsStore) UpdateWorkspaceTTL(ctx context.Context, arg database.Updat return r0 } -func (m metricsStore) UpdateWorkspacesDormantDeletingAtByTemplateID(ctx context.Context, arg database.UpdateWorkspacesDormantDeletingAtByTemplateIDParams) ([]database.Workspace, error) { +func (m metricsStore) UpdateWorkspacesDormantDeletingAtByTemplateID(ctx context.Context, arg database.UpdateWorkspacesDormantDeletingAtByTemplateIDParams) ([]database.WorkspaceTable, error) { start := time.Now() r0, r1 := m.s.UpdateWorkspacesDormantDeletingAtByTemplateID(ctx, arg) m.queryLatencies.WithLabelValues("UpdateWorkspacesDormantDeletingAtByTemplateID").Observe(time.Since(start).Seconds()) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index fb8bb1a55e00d..b3c7b9e7615d3 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -3234,10 +3234,10 @@ func (mr *MockStoreMockRecorder) GetWorkspaceBuildsCreatedAfter(arg0, arg1 any) } // GetWorkspaceByAgentID mocks base method. -func (m *MockStore) GetWorkspaceByAgentID(arg0 context.Context, arg1 uuid.UUID) (database.GetWorkspaceByAgentIDRow, error) { +func (m *MockStore) GetWorkspaceByAgentID(arg0 context.Context, arg1 uuid.UUID) (database.Workspace, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetWorkspaceByAgentID", arg0, arg1) - ret0, _ := ret[0].(database.GetWorkspaceByAgentIDRow) + ret0, _ := ret[0].(database.Workspace) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -3474,10 +3474,10 @@ func (mr *MockStoreMockRecorder) GetWorkspaces(arg0, arg1 any) *gomock.Call { } // GetWorkspacesEligibleForTransition mocks base method. -func (m *MockStore) GetWorkspacesEligibleForTransition(arg0 context.Context, arg1 time.Time) ([]database.Workspace, error) { +func (m *MockStore) GetWorkspacesEligibleForTransition(arg0 context.Context, arg1 time.Time) ([]database.WorkspaceTable, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetWorkspacesEligibleForTransition", arg0, arg1) - ret0, _ := ret[0].([]database.Workspace) + ret0, _ := ret[0].([]database.WorkspaceTable) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -4021,10 +4021,10 @@ func (mr *MockStoreMockRecorder) InsertUserLink(arg0, arg1 any) *gomock.Call { } // InsertWorkspace mocks base method. -func (m *MockStore) InsertWorkspace(arg0 context.Context, arg1 database.InsertWorkspaceParams) (database.Workspace, error) { +func (m *MockStore) InsertWorkspace(arg0 context.Context, arg1 database.InsertWorkspaceParams) (database.WorkspaceTable, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "InsertWorkspace", arg0, arg1) - ret0, _ := ret[0].(database.Workspace) + ret0, _ := ret[0].(database.WorkspaceTable) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -5041,10 +5041,10 @@ func (mr *MockStoreMockRecorder) UpdateUserStatus(arg0, arg1 any) *gomock.Call { } // UpdateWorkspace mocks base method. -func (m *MockStore) UpdateWorkspace(arg0 context.Context, arg1 database.UpdateWorkspaceParams) (database.Workspace, error) { +func (m *MockStore) UpdateWorkspace(arg0 context.Context, arg1 database.UpdateWorkspaceParams) (database.WorkspaceTable, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdateWorkspace", arg0, arg1) - ret0, _ := ret[0].(database.Workspace) + ret0, _ := ret[0].(database.WorkspaceTable) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -5224,10 +5224,10 @@ func (mr *MockStoreMockRecorder) UpdateWorkspaceDeletedByID(arg0, arg1 any) *gom } // UpdateWorkspaceDormantDeletingAt mocks base method. -func (m *MockStore) UpdateWorkspaceDormantDeletingAt(arg0 context.Context, arg1 database.UpdateWorkspaceDormantDeletingAtParams) (database.Workspace, error) { +func (m *MockStore) UpdateWorkspaceDormantDeletingAt(arg0 context.Context, arg1 database.UpdateWorkspaceDormantDeletingAtParams) (database.WorkspaceTable, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdateWorkspaceDormantDeletingAt", arg0, arg1) - ret0, _ := ret[0].(database.Workspace) + ret0, _ := ret[0].(database.WorkspaceTable) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -5296,10 +5296,10 @@ func (mr *MockStoreMockRecorder) UpdateWorkspaceTTL(arg0, arg1 any) *gomock.Call } // UpdateWorkspacesDormantDeletingAtByTemplateID mocks base method. -func (m *MockStore) UpdateWorkspacesDormantDeletingAtByTemplateID(arg0 context.Context, arg1 database.UpdateWorkspacesDormantDeletingAtByTemplateIDParams) ([]database.Workspace, error) { +func (m *MockStore) UpdateWorkspacesDormantDeletingAtByTemplateID(arg0 context.Context, arg1 database.UpdateWorkspacesDormantDeletingAtByTemplateIDParams) ([]database.WorkspaceTable, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdateWorkspacesDormantDeletingAtByTemplateID", arg0, arg1) - ret0, _ := ret[0].([]database.Workspace) + ret0, _ := ret[0].([]database.WorkspaceTable) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index 382cab743fb39..29e2c2d27ef18 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -1701,6 +1701,39 @@ CREATE TABLE workspaces ( COMMENT ON COLUMN workspaces.favorite IS 'Favorite is true if the workspace owner has favorited the workspace.'; +CREATE VIEW workspaces_expanded AS + SELECT workspaces.id, + workspaces.created_at, + workspaces.updated_at, + workspaces.owner_id, + workspaces.organization_id, + workspaces.template_id, + workspaces.deleted, + workspaces.name, + workspaces.autostart_schedule, + workspaces.ttl, + workspaces.last_used_at, + workspaces.dormant_at, + workspaces.deleting_at, + workspaces.automatic_updates, + workspaces.favorite, + COALESCE(visible_users.avatar_url, ''::text) AS owner_avatar_url, + COALESCE(visible_users.username, ''::text) AS owner_username, + COALESCE(organizations.name, ''::text) AS organization_name, + COALESCE(organizations.display_name, ''::text) AS organization_display_name, + COALESCE(organizations.icon, ''::text) AS organization_icon, + COALESCE(organizations.description, ''::text) AS organization_description, + COALESCE(templates.name, ''::character varying) AS template_name, + COALESCE(templates.display_name, ''::character varying) AS template_display_name, + COALESCE(templates.icon, ''::character varying) AS template_icon, + COALESCE(templates.description, ''::character varying) AS template_description + FROM (((workspaces + LEFT JOIN visible_users ON ((workspaces.owner_id = visible_users.id))) + LEFT JOIN organizations ON ((workspaces.organization_id = organizations.id))) + LEFT JOIN templates ON ((workspaces.template_id = templates.id))); + +COMMENT ON VIEW workspaces_expanded IS 'Joins in the display name information such as username, avatar, and organization name.'; + ALTER TABLE ONLY licenses ALTER COLUMN id SET DEFAULT nextval('licenses_id_seq'::regclass); ALTER TABLE ONLY provisioner_job_logs ALTER COLUMN id SET DEFAULT nextval('provisioner_job_logs_id_seq'::regclass); diff --git a/coderd/database/migrations/000262_workspace_with_names.down.sql b/coderd/database/migrations/000262_workspace_with_names.down.sql new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/coderd/database/migrations/000262_workspace_with_names.up.sql b/coderd/database/migrations/000262_workspace_with_names.up.sql new file mode 100644 index 0000000000000..392b003ddba8d --- /dev/null +++ b/coderd/database/migrations/000262_workspace_with_names.up.sql @@ -0,0 +1,33 @@ +CREATE VIEW + workspaces_expanded +AS +SELECT + workspaces.*, + -- Owner + coalesce(visible_users.avatar_url, '') AS owner_avatar_url, + coalesce(visible_users.username, '') AS owner_username, + -- Organization + coalesce(organizations.name, '') AS organization_name, + coalesce(organizations.display_name, '') AS organization_display_name, + coalesce(organizations.icon, '') AS organization_icon, + coalesce(organizations.description, '') AS organization_description, + -- Template + coalesce(templates.name, '') AS template_name, + coalesce(templates.display_name, '') AS template_display_name, + coalesce(templates.icon, '') AS template_icon, + coalesce(templates.description, '') AS template_description +FROM + workspaces + LEFT JOIN + visible_users + ON + workspaces.owner_id = visible_users.id + LEFT JOIN + organizations + ON workspaces.organization_id = organizations.id + LEFT JOIN + templates + ON workspaces.template_id = templates.id +; + +COMMENT ON VIEW workspaces_expanded IS 'Joins in the display name information such as username, avatar, and organization name.'; diff --git a/coderd/database/modelmethods.go b/coderd/database/modelmethods.go index 846de6e36aa47..cabf36419e894 100644 --- a/coderd/database/modelmethods.go +++ b/coderd/database/modelmethods.go @@ -192,12 +192,36 @@ func (gm GroupMember) RBACObject() rbac.Object { return rbac.ResourceGroupMember.WithID(gm.UserID).InOrg(gm.OrganizationID).WithOwner(gm.UserID.String()) } -func (w GetWorkspaceByAgentIDRow) RBACObject() rbac.Object { - return w.Workspace.RBACObject() +// WorkspaceTable converts a Workspace to it's reduced version. +// A more generalized solution is to use json marshalling to +// consistently keep these two structs in sync. +// That would be a lot of overhead, and a more costly unit test is +// written to make sure these match up. +func (w Workspace) WorkspaceTable() WorkspaceTable { + return WorkspaceTable{ + ID: w.ID, + CreatedAt: w.CreatedAt, + UpdatedAt: w.UpdatedAt, + OwnerID: w.OwnerID, + OrganizationID: w.OrganizationID, + TemplateID: w.TemplateID, + Deleted: w.Deleted, + Name: w.Name, + AutostartSchedule: w.AutostartSchedule, + Ttl: w.Ttl, + LastUsedAt: w.LastUsedAt, + DormantAt: w.DormantAt, + DeletingAt: w.DeletingAt, + AutomaticUpdates: w.AutomaticUpdates, + Favorite: w.Favorite, + } } func (w Workspace) RBACObject() rbac.Object { - // If a workspace is locked it cannot be accessed. + return w.WorkspaceTable().RBACObject() +} + +func (w WorkspaceTable) RBACObject() rbac.Object { if w.DormantAt.Valid { return w.DormantRBAC() } @@ -207,7 +231,7 @@ func (w Workspace) RBACObject() rbac.Object { WithOwner(w.OwnerID.String()) } -func (w Workspace) DormantRBAC() rbac.Object { +func (w WorkspaceTable) DormantRBAC() rbac.Object { return rbac.ResourceWorkspaceDormant. WithID(w.ID). InOrg(w.OrganizationID). diff --git a/coderd/database/modelqueries.go b/coderd/database/modelqueries.go index 1274608a7d276..9888027e01559 100644 --- a/coderd/database/modelqueries.go +++ b/coderd/database/modelqueries.go @@ -288,10 +288,18 @@ func (q *sqlQuerier) GetAuthorizedWorkspaces(ctx context.Context, arg GetWorkspa &i.DeletingAt, &i.AutomaticUpdates, &i.Favorite, + &i.OwnerAvatarUrl, + &i.OwnerUsername, + &i.OrganizationName, + &i.OrganizationDisplayName, + &i.OrganizationIcon, + &i.OrganizationDescription, &i.TemplateName, + &i.TemplateDisplayName, + &i.TemplateIcon, + &i.TemplateDescription, &i.TemplateVersionID, &i.TemplateVersionName, - &i.Username, &i.LatestBuildCompletedAt, &i.LatestBuildCanceledAt, &i.LatestBuildError, diff --git a/coderd/database/modelqueries_internal_test.go b/coderd/database/modelqueries_internal_test.go index 4977120e88135..773dfb9eea82d 100644 --- a/coderd/database/modelqueries_internal_test.go +++ b/coderd/database/modelqueries_internal_test.go @@ -1,6 +1,8 @@ package database import ( + "fmt" + "reflect" "testing" "github.com/stretchr/testify/require" @@ -13,3 +15,75 @@ func TestIsAuthorizedQuery(t *testing.T) { _, err := insertAuthorizedFilter(query, "") require.ErrorContains(t, err, "does not contain authorized replace string", "ensure replace string") } + +// TestWorkspaceTableConvert verifies all workspace fields are converted +// when reducing a `Workspace` to a `WorkspaceTable`. +func TestWorkspaceTableConvert(t *testing.T) { + t.Parallel() + + var workspace Workspace + err := populateStruct(&workspace) + require.NoError(t, err) + +} + +func populateStruct(s interface{}) error { + v := reflect.ValueOf(s) + if v.Kind() != reflect.Ptr || v.IsNil() { + return fmt.Errorf("s must be a non-nil pointer") + } + + v = v.Elem() + if v.Kind() != reflect.Struct { + return fmt.Errorf("s must be a pointer to a struct") + } + + t := v.Type() + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + fieldName := field.Name + + fieldValue := v.Field(i) + if !fieldValue.CanSet() { + continue // Skip if field is unexported + } + + switch fieldValue.Kind() { + case reflect.Struct: + if err := populateStruct(fieldValue.Addr().Interface()); err != nil { + return fmt.Errorf("%s : %w", fieldName, err) + } + case reflect.String: + fieldValue.SetString("foo") + case reflect.Invalid: + case reflect.Bool: + case reflect.Int: + case reflect.Int8: + case reflect.Int16: + case reflect.Int32: + case reflect.Int64: + case reflect.Uint: + case reflect.Uint8: + case reflect.Uint16: + case reflect.Uint32: + case reflect.Uint64: + case reflect.Uintptr: + case reflect.Float32: + case reflect.Float64: + case reflect.Complex64: + case reflect.Complex128: + case reflect.Array: + case reflect.Chan: + case reflect.Func: + case reflect.Interface: + case reflect.Map: + case reflect.Pointer: + case reflect.Slice: + case reflect.UnsafePointer: + default: + return fmt.Errorf("unsupported kind %s", fieldValue.Kind()) + } + } + + return nil +} diff --git a/coderd/database/models.go b/coderd/database/models.go index c44aa6011bc22..0794546af7a22 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.27.0 package database @@ -2902,23 +2902,33 @@ type VisibleUser struct { AvatarURL string `db:"avatar_url" json:"avatar_url"` } +// Joins in the display name information such as username, avatar, and organization name. type Workspace struct { - ID uuid.UUID `db:"id" json:"id"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - UpdatedAt time.Time `db:"updated_at" json:"updated_at"` - OwnerID uuid.UUID `db:"owner_id" json:"owner_id"` - OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` - TemplateID uuid.UUID `db:"template_id" json:"template_id"` - Deleted bool `db:"deleted" json:"deleted"` - Name string `db:"name" json:"name"` - AutostartSchedule sql.NullString `db:"autostart_schedule" json:"autostart_schedule"` - Ttl sql.NullInt64 `db:"ttl" json:"ttl"` - LastUsedAt time.Time `db:"last_used_at" json:"last_used_at"` - DormantAt sql.NullTime `db:"dormant_at" json:"dormant_at"` - DeletingAt sql.NullTime `db:"deleting_at" json:"deleting_at"` - AutomaticUpdates AutomaticUpdates `db:"automatic_updates" json:"automatic_updates"` - // Favorite is true if the workspace owner has favorited the workspace. - Favorite bool `db:"favorite" json:"favorite"` + ID uuid.UUID `db:"id" json:"id"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` + OwnerID uuid.UUID `db:"owner_id" json:"owner_id"` + OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` + TemplateID uuid.UUID `db:"template_id" json:"template_id"` + Deleted bool `db:"deleted" json:"deleted"` + Name string `db:"name" json:"name"` + AutostartSchedule sql.NullString `db:"autostart_schedule" json:"autostart_schedule"` + Ttl sql.NullInt64 `db:"ttl" json:"ttl"` + LastUsedAt time.Time `db:"last_used_at" json:"last_used_at"` + DormantAt sql.NullTime `db:"dormant_at" json:"dormant_at"` + DeletingAt sql.NullTime `db:"deleting_at" json:"deleting_at"` + AutomaticUpdates AutomaticUpdates `db:"automatic_updates" json:"automatic_updates"` + Favorite bool `db:"favorite" json:"favorite"` + OwnerAvatarUrl string `db:"owner_avatar_url" json:"owner_avatar_url"` + OwnerUsername string `db:"owner_username" json:"owner_username"` + OrganizationName string `db:"organization_name" json:"organization_name"` + OrganizationDisplayName string `db:"organization_display_name" json:"organization_display_name"` + OrganizationIcon string `db:"organization_icon" json:"organization_icon"` + OrganizationDescription string `db:"organization_description" json:"organization_description"` + TemplateName string `db:"template_name" json:"template_name"` + TemplateDisplayName string `db:"template_display_name" json:"template_display_name"` + TemplateIcon string `db:"template_icon" json:"template_icon"` + TemplateDescription string `db:"template_description" json:"template_description"` } type WorkspaceAgent struct { @@ -3184,3 +3194,22 @@ type WorkspaceResourceMetadatum struct { Sensitive bool `db:"sensitive" json:"sensitive"` ID int64 `db:"id" json:"id"` } + +type WorkspaceTable struct { + ID uuid.UUID `db:"id" json:"id"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` + OwnerID uuid.UUID `db:"owner_id" json:"owner_id"` + OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` + TemplateID uuid.UUID `db:"template_id" json:"template_id"` + Deleted bool `db:"deleted" json:"deleted"` + Name string `db:"name" json:"name"` + AutostartSchedule sql.NullString `db:"autostart_schedule" json:"autostart_schedule"` + Ttl sql.NullInt64 `db:"ttl" json:"ttl"` + LastUsedAt time.Time `db:"last_used_at" json:"last_used_at"` + DormantAt sql.NullTime `db:"dormant_at" json:"dormant_at"` + DeletingAt sql.NullTime `db:"deleting_at" json:"deleting_at"` + AutomaticUpdates AutomaticUpdates `db:"automatic_updates" json:"automatic_updates"` + // Favorite is true if the workspace owner has favorited the workspace. + Favorite bool `db:"favorite" json:"favorite"` +} diff --git a/coderd/database/querier.go b/coderd/database/querier.go index cb126f83af32f..d8c442439735d 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.27.0 package database @@ -319,7 +319,7 @@ type sqlcQuerier interface { GetWorkspaceBuildStatsByTemplates(ctx context.Context, since time.Time) ([]GetWorkspaceBuildStatsByTemplatesRow, error) GetWorkspaceBuildsByWorkspaceID(ctx context.Context, arg GetWorkspaceBuildsByWorkspaceIDParams) ([]WorkspaceBuild, error) GetWorkspaceBuildsCreatedAfter(ctx context.Context, createdAt time.Time) ([]WorkspaceBuild, error) - GetWorkspaceByAgentID(ctx context.Context, agentID uuid.UUID) (GetWorkspaceByAgentIDRow, error) + GetWorkspaceByAgentID(ctx context.Context, agentID uuid.UUID) (Workspace, error) GetWorkspaceByID(ctx context.Context, id uuid.UUID) (Workspace, error) GetWorkspaceByOwnerIDAndName(ctx context.Context, arg GetWorkspaceByOwnerIDAndNameParams) (Workspace, error) GetWorkspaceByWorkspaceAppID(ctx context.Context, workspaceAppID uuid.UUID) (Workspace, error) @@ -345,7 +345,7 @@ type sqlcQuerier interface { // It has to be a CTE because the set returning function 'unnest' cannot // be used in a WHERE clause. GetWorkspaces(ctx context.Context, arg GetWorkspacesParams) ([]GetWorkspacesRow, error) - GetWorkspacesEligibleForTransition(ctx context.Context, now time.Time) ([]Workspace, error) + GetWorkspacesEligibleForTransition(ctx context.Context, now time.Time) ([]WorkspaceTable, error) InsertAPIKey(ctx context.Context, arg InsertAPIKeyParams) (APIKey, error) // We use the organization_id as the id // for simplicity since all users is @@ -391,7 +391,7 @@ type sqlcQuerier interface { // InsertUserGroupsByName adds a user to all provided groups, if they exist. InsertUserGroupsByName(ctx context.Context, arg InsertUserGroupsByNameParams) error InsertUserLink(ctx context.Context, arg InsertUserLinkParams) (UserLink, error) - InsertWorkspace(ctx context.Context, arg InsertWorkspaceParams) (Workspace, error) + InsertWorkspace(ctx context.Context, arg InsertWorkspaceParams) (WorkspaceTable, error) InsertWorkspaceAgent(ctx context.Context, arg InsertWorkspaceAgentParams) (WorkspaceAgent, error) InsertWorkspaceAgentLogSources(ctx context.Context, arg InsertWorkspaceAgentLogSourcesParams) ([]WorkspaceAgentLogSource, error) InsertWorkspaceAgentLogs(ctx context.Context, arg InsertWorkspaceAgentLogsParams) ([]WorkspaceAgentLog, error) @@ -469,7 +469,7 @@ type sqlcQuerier interface { UpdateUserQuietHoursSchedule(ctx context.Context, arg UpdateUserQuietHoursScheduleParams) (User, error) UpdateUserRoles(ctx context.Context, arg UpdateUserRolesParams) (User, error) UpdateUserStatus(ctx context.Context, arg UpdateUserStatusParams) (User, error) - UpdateWorkspace(ctx context.Context, arg UpdateWorkspaceParams) (Workspace, error) + UpdateWorkspace(ctx context.Context, arg UpdateWorkspaceParams) (WorkspaceTable, error) UpdateWorkspaceAgentConnectionByID(ctx context.Context, arg UpdateWorkspaceAgentConnectionByIDParams) error UpdateWorkspaceAgentLifecycleStateByID(ctx context.Context, arg UpdateWorkspaceAgentLifecycleStateByIDParams) error UpdateWorkspaceAgentLogOverflowByID(ctx context.Context, arg UpdateWorkspaceAgentLogOverflowByIDParams) error @@ -482,13 +482,13 @@ type sqlcQuerier interface { UpdateWorkspaceBuildDeadlineByID(ctx context.Context, arg UpdateWorkspaceBuildDeadlineByIDParams) error UpdateWorkspaceBuildProvisionerStateByID(ctx context.Context, arg UpdateWorkspaceBuildProvisionerStateByIDParams) error UpdateWorkspaceDeletedByID(ctx context.Context, arg UpdateWorkspaceDeletedByIDParams) error - UpdateWorkspaceDormantDeletingAt(ctx context.Context, arg UpdateWorkspaceDormantDeletingAtParams) (Workspace, error) + UpdateWorkspaceDormantDeletingAt(ctx context.Context, arg UpdateWorkspaceDormantDeletingAtParams) (WorkspaceTable, error) UpdateWorkspaceLastUsedAt(ctx context.Context, arg UpdateWorkspaceLastUsedAtParams) error // This allows editing the properties of a workspace proxy. UpdateWorkspaceProxy(ctx context.Context, arg UpdateWorkspaceProxyParams) (WorkspaceProxy, error) UpdateWorkspaceProxyDeleted(ctx context.Context, arg UpdateWorkspaceProxyDeletedParams) error UpdateWorkspaceTTL(ctx context.Context, arg UpdateWorkspaceTTLParams) error - UpdateWorkspacesDormantDeletingAtByTemplateID(ctx context.Context, arg UpdateWorkspacesDormantDeletingAtByTemplateIDParams) ([]Workspace, error) + UpdateWorkspacesDormantDeletingAtByTemplateID(ctx context.Context, arg UpdateWorkspacesDormantDeletingAtByTemplateIDParams) ([]WorkspaceTable, error) UpsertAnnouncementBanners(ctx context.Context, value string) error UpsertAppSecurityKey(ctx context.Context, value string) error UpsertApplicationName(ctx context.Context, value string) error diff --git a/coderd/database/querier_test.go b/coderd/database/querier_test.go index dfa024464de9b..58c9626f2c9bf 100644 --- a/coderd/database/querier_test.go +++ b/coderd/database/querier_test.go @@ -416,7 +416,7 @@ func TestGetWorkspaceAgentUsageStatsAndLabels(t *testing.T) { OrganizationID: org.ID, CreatedBy: user1.ID, }) - workspace1 := dbgen.Workspace(t, db, database.Workspace{ + workspace1 := dbgen.Workspace(t, db, database.WorkspaceTable{ OwnerID: user1.ID, OrganizationID: org.ID, TemplateID: template1.ID, @@ -435,7 +435,7 @@ func TestGetWorkspaceAgentUsageStatsAndLabels(t *testing.T) { CreatedBy: user1.ID, OrganizationID: org.ID, }) - workspace2 := dbgen.Workspace(t, db, database.Workspace{ + workspace2 := dbgen.Workspace(t, db, database.WorkspaceTable{ OwnerID: user2.ID, OrganizationID: org.ID, TemplateID: template2.ID, @@ -577,7 +577,7 @@ func TestGetWorkspaceAgentUsageStatsAndLabels(t *testing.T) { OrganizationID: org.ID, CreatedBy: user.ID, }) - workspace := dbgen.Workspace(t, db, database.Workspace{ + workspace := dbgen.Workspace(t, db, database.WorkspaceTable{ OwnerID: user.ID, OrganizationID: org.ID, TemplateID: template.ID, @@ -1596,7 +1596,7 @@ func createTemplateVersion(t testing.TB, db database.Store, tpl database.Templat dbgen.ProvisionerJob(t, db, nil, j) if args.CreateWorkspace { - wrk := dbgen.Workspace(t, db, database.Workspace{ + wrk := dbgen.Workspace(t, db, database.WorkspaceTable{ CreatedAt: time.Time{}, UpdatedAt: time.Time{}, OwnerID: tpl.CreatedBy, diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 913d3a040e8b8..4eb7c251f40a5 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.27.0 package database @@ -11117,7 +11117,7 @@ WHERE ` type GetWorkspaceAgentAndLatestBuildByAuthTokenRow struct { - Workspace Workspace `db:"workspace" json:"workspace"` + WorkspaceTable WorkspaceTable `db:"workspace_table" json:"workspace_table"` WorkspaceAgent WorkspaceAgent `db:"workspace_agent" json:"workspace_agent"` WorkspaceBuild WorkspaceBuild `db:"workspace_build" json:"workspace_build"` } @@ -11126,21 +11126,21 @@ func (q *sqlQuerier) GetWorkspaceAgentAndLatestBuildByAuthToken(ctx context.Cont row := q.db.QueryRowContext(ctx, getWorkspaceAgentAndLatestBuildByAuthToken, authToken) var i GetWorkspaceAgentAndLatestBuildByAuthTokenRow err := row.Scan( - &i.Workspace.ID, - &i.Workspace.CreatedAt, - &i.Workspace.UpdatedAt, - &i.Workspace.OwnerID, - &i.Workspace.OrganizationID, - &i.Workspace.TemplateID, - &i.Workspace.Deleted, - &i.Workspace.Name, - &i.Workspace.AutostartSchedule, - &i.Workspace.Ttl, - &i.Workspace.LastUsedAt, - &i.Workspace.DormantAt, - &i.Workspace.DeletingAt, - &i.Workspace.AutomaticUpdates, - &i.Workspace.Favorite, + &i.WorkspaceTable.ID, + &i.WorkspaceTable.CreatedAt, + &i.WorkspaceTable.UpdatedAt, + &i.WorkspaceTable.OwnerID, + &i.WorkspaceTable.OrganizationID, + &i.WorkspaceTable.TemplateID, + &i.WorkspaceTable.Deleted, + &i.WorkspaceTable.Name, + &i.WorkspaceTable.AutostartSchedule, + &i.WorkspaceTable.Ttl, + &i.WorkspaceTable.LastUsedAt, + &i.WorkspaceTable.DormantAt, + &i.WorkspaceTable.DeletingAt, + &i.WorkspaceTable.AutomaticUpdates, + &i.WorkspaceTable.Favorite, &i.WorkspaceAgent.ID, &i.WorkspaceAgent.CreatedAt, &i.WorkspaceAgent.UpdatedAt, @@ -14539,12 +14539,9 @@ func (q *sqlQuerier) GetDeploymentWorkspaceStats(ctx context.Context) (GetDeploy const getWorkspaceByAgentID = `-- name: GetWorkspaceByAgentID :one SELECT - workspaces.id, workspaces.created_at, workspaces.updated_at, workspaces.owner_id, workspaces.organization_id, workspaces.template_id, workspaces.deleted, workspaces.name, workspaces.autostart_schedule, workspaces.ttl, workspaces.last_used_at, workspaces.dormant_at, workspaces.deleting_at, workspaces.automatic_updates, workspaces.favorite, - templates.name as template_name + id, created_at, updated_at, owner_id, organization_id, template_id, deleted, name, autostart_schedule, ttl, last_used_at, dormant_at, deleting_at, automatic_updates, favorite, owner_avatar_url, owner_username, organization_name, organization_display_name, organization_icon, organization_description, template_name, template_display_name, template_icon, template_description FROM - workspaces -INNER JOIN - templates ON workspaces.template_id = templates.id + workspaces_expanded as workspaces WHERE workspaces.id = ( SELECT @@ -14570,40 +14567,44 @@ WHERE ) ` -type GetWorkspaceByAgentIDRow struct { - Workspace Workspace `db:"workspace" json:"workspace"` - TemplateName string `db:"template_name" json:"template_name"` -} - -func (q *sqlQuerier) GetWorkspaceByAgentID(ctx context.Context, agentID uuid.UUID) (GetWorkspaceByAgentIDRow, error) { +func (q *sqlQuerier) GetWorkspaceByAgentID(ctx context.Context, agentID uuid.UUID) (Workspace, error) { row := q.db.QueryRowContext(ctx, getWorkspaceByAgentID, agentID) - var i GetWorkspaceByAgentIDRow + var i Workspace err := row.Scan( - &i.Workspace.ID, - &i.Workspace.CreatedAt, - &i.Workspace.UpdatedAt, - &i.Workspace.OwnerID, - &i.Workspace.OrganizationID, - &i.Workspace.TemplateID, - &i.Workspace.Deleted, - &i.Workspace.Name, - &i.Workspace.AutostartSchedule, - &i.Workspace.Ttl, - &i.Workspace.LastUsedAt, - &i.Workspace.DormantAt, - &i.Workspace.DeletingAt, - &i.Workspace.AutomaticUpdates, - &i.Workspace.Favorite, + &i.ID, + &i.CreatedAt, + &i.UpdatedAt, + &i.OwnerID, + &i.OrganizationID, + &i.TemplateID, + &i.Deleted, + &i.Name, + &i.AutostartSchedule, + &i.Ttl, + &i.LastUsedAt, + &i.DormantAt, + &i.DeletingAt, + &i.AutomaticUpdates, + &i.Favorite, + &i.OwnerAvatarUrl, + &i.OwnerUsername, + &i.OrganizationName, + &i.OrganizationDisplayName, + &i.OrganizationIcon, + &i.OrganizationDescription, &i.TemplateName, + &i.TemplateDisplayName, + &i.TemplateIcon, + &i.TemplateDescription, ) return i, err } const getWorkspaceByID = `-- name: GetWorkspaceByID :one SELECT - id, created_at, updated_at, owner_id, organization_id, template_id, deleted, name, autostart_schedule, ttl, last_used_at, dormant_at, deleting_at, automatic_updates, favorite + id, created_at, updated_at, owner_id, organization_id, template_id, deleted, name, autostart_schedule, ttl, last_used_at, dormant_at, deleting_at, automatic_updates, favorite, owner_avatar_url, owner_username, organization_name, organization_display_name, organization_icon, organization_description, template_name, template_display_name, template_icon, template_description FROM - workspaces + workspaces_expanded WHERE id = $1 LIMIT @@ -14629,15 +14630,25 @@ func (q *sqlQuerier) GetWorkspaceByID(ctx context.Context, id uuid.UUID) (Worksp &i.DeletingAt, &i.AutomaticUpdates, &i.Favorite, + &i.OwnerAvatarUrl, + &i.OwnerUsername, + &i.OrganizationName, + &i.OrganizationDisplayName, + &i.OrganizationIcon, + &i.OrganizationDescription, + &i.TemplateName, + &i.TemplateDisplayName, + &i.TemplateIcon, + &i.TemplateDescription, ) return i, err } const getWorkspaceByOwnerIDAndName = `-- name: GetWorkspaceByOwnerIDAndName :one SELECT - id, created_at, updated_at, owner_id, organization_id, template_id, deleted, name, autostart_schedule, ttl, last_used_at, dormant_at, deleting_at, automatic_updates, favorite + id, created_at, updated_at, owner_id, organization_id, template_id, deleted, name, autostart_schedule, ttl, last_used_at, dormant_at, deleting_at, automatic_updates, favorite, owner_avatar_url, owner_username, organization_name, organization_display_name, organization_icon, organization_description, template_name, template_display_name, template_icon, template_description FROM - workspaces + workspaces_expanded as workspaces WHERE owner_id = $1 AND deleted = $2 @@ -14670,15 +14681,25 @@ func (q *sqlQuerier) GetWorkspaceByOwnerIDAndName(ctx context.Context, arg GetWo &i.DeletingAt, &i.AutomaticUpdates, &i.Favorite, + &i.OwnerAvatarUrl, + &i.OwnerUsername, + &i.OrganizationName, + &i.OrganizationDisplayName, + &i.OrganizationIcon, + &i.OrganizationDescription, + &i.TemplateName, + &i.TemplateDisplayName, + &i.TemplateIcon, + &i.TemplateDescription, ) return i, err } const getWorkspaceByWorkspaceAppID = `-- name: GetWorkspaceByWorkspaceAppID :one SELECT - id, created_at, updated_at, owner_id, organization_id, template_id, deleted, name, autostart_schedule, ttl, last_used_at, dormant_at, deleting_at, automatic_updates, favorite + id, created_at, updated_at, owner_id, organization_id, template_id, deleted, name, autostart_schedule, ttl, last_used_at, dormant_at, deleting_at, automatic_updates, favorite, owner_avatar_url, owner_username, organization_name, organization_display_name, organization_icon, organization_description, template_name, template_display_name, template_icon, template_description FROM - workspaces + workspaces_expanded as workspaces WHERE workspaces.id = ( SELECT @@ -14730,6 +14751,16 @@ func (q *sqlQuerier) GetWorkspaceByWorkspaceAppID(ctx context.Context, workspace &i.DeletingAt, &i.AutomaticUpdates, &i.Favorite, + &i.OwnerAvatarUrl, + &i.OwnerUsername, + &i.OrganizationName, + &i.OrganizationDisplayName, + &i.OrganizationIcon, + &i.OrganizationDescription, + &i.TemplateName, + &i.TemplateDisplayName, + &i.TemplateIcon, + &i.TemplateDescription, ) return i, err } @@ -14781,18 +14812,16 @@ SELECT ), filtered_workspaces AS ( SELECT - workspaces.id, workspaces.created_at, workspaces.updated_at, workspaces.owner_id, workspaces.organization_id, workspaces.template_id, workspaces.deleted, workspaces.name, workspaces.autostart_schedule, workspaces.ttl, workspaces.last_used_at, workspaces.dormant_at, workspaces.deleting_at, workspaces.automatic_updates, workspaces.favorite, - COALESCE(template.name, 'unknown') as template_name, + workspaces.id, workspaces.created_at, workspaces.updated_at, workspaces.owner_id, workspaces.organization_id, workspaces.template_id, workspaces.deleted, workspaces.name, workspaces.autostart_schedule, workspaces.ttl, workspaces.last_used_at, workspaces.dormant_at, workspaces.deleting_at, workspaces.automatic_updates, workspaces.favorite, workspaces.owner_avatar_url, workspaces.owner_username, workspaces.organization_name, workspaces.organization_display_name, workspaces.organization_icon, workspaces.organization_description, workspaces.template_name, workspaces.template_display_name, workspaces.template_icon, workspaces.template_description, latest_build.template_version_id, latest_build.template_version_name, - users.username as username, latest_build.completed_at as latest_build_completed_at, latest_build.canceled_at as latest_build_canceled_at, latest_build.error as latest_build_error, latest_build.transition as latest_build_transition, latest_build.job_status as latest_build_status FROM - workspaces + workspaces_expanded as workspaces JOIN users ON @@ -15023,7 +15052,7 @@ WHERE -- @authorize_filter ), filtered_workspaces_order AS ( SELECT - fw.id, fw.created_at, fw.updated_at, fw.owner_id, fw.organization_id, fw.template_id, fw.deleted, fw.name, fw.autostart_schedule, fw.ttl, fw.last_used_at, fw.dormant_at, fw.deleting_at, fw.automatic_updates, fw.favorite, fw.template_name, fw.template_version_id, fw.template_version_name, fw.username, fw.latest_build_completed_at, fw.latest_build_canceled_at, fw.latest_build_error, fw.latest_build_transition, fw.latest_build_status + fw.id, fw.created_at, fw.updated_at, fw.owner_id, fw.organization_id, fw.template_id, fw.deleted, fw.name, fw.autostart_schedule, fw.ttl, fw.last_used_at, fw.dormant_at, fw.deleting_at, fw.automatic_updates, fw.favorite, fw.owner_avatar_url, fw.owner_username, fw.organization_name, fw.organization_display_name, fw.organization_icon, fw.organization_description, fw.template_name, fw.template_display_name, fw.template_icon, fw.template_description, fw.template_version_id, fw.template_version_name, fw.latest_build_completed_at, fw.latest_build_canceled_at, fw.latest_build_error, fw.latest_build_transition, fw.latest_build_status FROM filtered_workspaces fw ORDER BY @@ -15044,7 +15073,7 @@ WHERE $20 ), filtered_workspaces_order_with_summary AS ( SELECT - fwo.id, fwo.created_at, fwo.updated_at, fwo.owner_id, fwo.organization_id, fwo.template_id, fwo.deleted, fwo.name, fwo.autostart_schedule, fwo.ttl, fwo.last_used_at, fwo.dormant_at, fwo.deleting_at, fwo.automatic_updates, fwo.favorite, fwo.template_name, fwo.template_version_id, fwo.template_version_name, fwo.username, fwo.latest_build_completed_at, fwo.latest_build_canceled_at, fwo.latest_build_error, fwo.latest_build_transition, fwo.latest_build_status + fwo.id, fwo.created_at, fwo.updated_at, fwo.owner_id, fwo.organization_id, fwo.template_id, fwo.deleted, fwo.name, fwo.autostart_schedule, fwo.ttl, fwo.last_used_at, fwo.dormant_at, fwo.deleting_at, fwo.automatic_updates, fwo.favorite, fwo.owner_avatar_url, fwo.owner_username, fwo.organization_name, fwo.organization_display_name, fwo.organization_icon, fwo.organization_description, fwo.template_name, fwo.template_display_name, fwo.template_icon, fwo.template_description, fwo.template_version_id, fwo.template_version_name, fwo.latest_build_completed_at, fwo.latest_build_canceled_at, fwo.latest_build_error, fwo.latest_build_transition, fwo.latest_build_status FROM filtered_workspaces_order fwo -- Return a technical summary row with total count of workspaces. @@ -15085,7 +15114,7 @@ WHERE filtered_workspaces ) SELECT - fwos.id, fwos.created_at, fwos.updated_at, fwos.owner_id, fwos.organization_id, fwos.template_id, fwos.deleted, fwos.name, fwos.autostart_schedule, fwos.ttl, fwos.last_used_at, fwos.dormant_at, fwos.deleting_at, fwos.automatic_updates, fwos.favorite, fwos.template_name, fwos.template_version_id, fwos.template_version_name, fwos.username, fwos.latest_build_completed_at, fwos.latest_build_canceled_at, fwos.latest_build_error, fwos.latest_build_transition, fwos.latest_build_status, + fwos.id, fwos.created_at, fwos.updated_at, fwos.owner_id, fwos.organization_id, fwos.template_id, fwos.deleted, fwos.name, fwos.autostart_schedule, fwos.ttl, fwos.last_used_at, fwos.dormant_at, fwos.deleting_at, fwos.automatic_updates, fwos.favorite, fwos.owner_avatar_url, fwos.owner_username, fwos.organization_name, fwos.organization_display_name, fwos.organization_icon, fwos.organization_description, fwos.template_name, fwos.template_display_name, fwos.template_icon, fwos.template_description, fwos.template_version_id, fwos.template_version_name, fwos.latest_build_completed_at, fwos.latest_build_canceled_at, fwos.latest_build_error, fwos.latest_build_transition, fwos.latest_build_status, tc.count FROM filtered_workspaces_order_with_summary fwos @@ -15119,31 +15148,39 @@ type GetWorkspacesParams struct { } type GetWorkspacesRow struct { - ID uuid.UUID `db:"id" json:"id"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - UpdatedAt time.Time `db:"updated_at" json:"updated_at"` - OwnerID uuid.UUID `db:"owner_id" json:"owner_id"` - OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` - TemplateID uuid.UUID `db:"template_id" json:"template_id"` - Deleted bool `db:"deleted" json:"deleted"` - Name string `db:"name" json:"name"` - AutostartSchedule sql.NullString `db:"autostart_schedule" json:"autostart_schedule"` - Ttl sql.NullInt64 `db:"ttl" json:"ttl"` - LastUsedAt time.Time `db:"last_used_at" json:"last_used_at"` - DormantAt sql.NullTime `db:"dormant_at" json:"dormant_at"` - DeletingAt sql.NullTime `db:"deleting_at" json:"deleting_at"` - AutomaticUpdates AutomaticUpdates `db:"automatic_updates" json:"automatic_updates"` - Favorite bool `db:"favorite" json:"favorite"` - TemplateName string `db:"template_name" json:"template_name"` - TemplateVersionID uuid.UUID `db:"template_version_id" json:"template_version_id"` - TemplateVersionName sql.NullString `db:"template_version_name" json:"template_version_name"` - Username string `db:"username" json:"username"` - LatestBuildCompletedAt sql.NullTime `db:"latest_build_completed_at" json:"latest_build_completed_at"` - LatestBuildCanceledAt sql.NullTime `db:"latest_build_canceled_at" json:"latest_build_canceled_at"` - LatestBuildError sql.NullString `db:"latest_build_error" json:"latest_build_error"` - LatestBuildTransition WorkspaceTransition `db:"latest_build_transition" json:"latest_build_transition"` - LatestBuildStatus ProvisionerJobStatus `db:"latest_build_status" json:"latest_build_status"` - Count int64 `db:"count" json:"count"` + ID uuid.UUID `db:"id" json:"id"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` + OwnerID uuid.UUID `db:"owner_id" json:"owner_id"` + OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` + TemplateID uuid.UUID `db:"template_id" json:"template_id"` + Deleted bool `db:"deleted" json:"deleted"` + Name string `db:"name" json:"name"` + AutostartSchedule sql.NullString `db:"autostart_schedule" json:"autostart_schedule"` + Ttl sql.NullInt64 `db:"ttl" json:"ttl"` + LastUsedAt time.Time `db:"last_used_at" json:"last_used_at"` + DormantAt sql.NullTime `db:"dormant_at" json:"dormant_at"` + DeletingAt sql.NullTime `db:"deleting_at" json:"deleting_at"` + AutomaticUpdates AutomaticUpdates `db:"automatic_updates" json:"automatic_updates"` + Favorite bool `db:"favorite" json:"favorite"` + OwnerAvatarUrl string `db:"owner_avatar_url" json:"owner_avatar_url"` + OwnerUsername string `db:"owner_username" json:"owner_username"` + OrganizationName string `db:"organization_name" json:"organization_name"` + OrganizationDisplayName string `db:"organization_display_name" json:"organization_display_name"` + OrganizationIcon string `db:"organization_icon" json:"organization_icon"` + OrganizationDescription string `db:"organization_description" json:"organization_description"` + TemplateName string `db:"template_name" json:"template_name"` + TemplateDisplayName string `db:"template_display_name" json:"template_display_name"` + TemplateIcon string `db:"template_icon" json:"template_icon"` + TemplateDescription string `db:"template_description" json:"template_description"` + TemplateVersionID uuid.UUID `db:"template_version_id" json:"template_version_id"` + TemplateVersionName sql.NullString `db:"template_version_name" json:"template_version_name"` + LatestBuildCompletedAt sql.NullTime `db:"latest_build_completed_at" json:"latest_build_completed_at"` + LatestBuildCanceledAt sql.NullTime `db:"latest_build_canceled_at" json:"latest_build_canceled_at"` + LatestBuildError sql.NullString `db:"latest_build_error" json:"latest_build_error"` + LatestBuildTransition WorkspaceTransition `db:"latest_build_transition" json:"latest_build_transition"` + LatestBuildStatus ProvisionerJobStatus `db:"latest_build_status" json:"latest_build_status"` + Count int64 `db:"count" json:"count"` } // build_params is used to filter by build parameters if present. @@ -15197,10 +15234,18 @@ func (q *sqlQuerier) GetWorkspaces(ctx context.Context, arg GetWorkspacesParams) &i.DeletingAt, &i.AutomaticUpdates, &i.Favorite, + &i.OwnerAvatarUrl, + &i.OwnerUsername, + &i.OrganizationName, + &i.OrganizationDisplayName, + &i.OrganizationIcon, + &i.OrganizationDescription, &i.TemplateName, + &i.TemplateDisplayName, + &i.TemplateIcon, + &i.TemplateDescription, &i.TemplateVersionID, &i.TemplateVersionName, - &i.Username, &i.LatestBuildCompletedAt, &i.LatestBuildCanceledAt, &i.LatestBuildError, @@ -15295,15 +15340,15 @@ WHERE ) AND workspaces.deleted = 'false' ` -func (q *sqlQuerier) GetWorkspacesEligibleForTransition(ctx context.Context, now time.Time) ([]Workspace, error) { +func (q *sqlQuerier) GetWorkspacesEligibleForTransition(ctx context.Context, now time.Time) ([]WorkspaceTable, error) { rows, err := q.db.QueryContext(ctx, getWorkspacesEligibleForTransition, now) if err != nil { return nil, err } defer rows.Close() - var items []Workspace + var items []WorkspaceTable for rows.Next() { - var i Workspace + var i WorkspaceTable if err := rows.Scan( &i.ID, &i.CreatedAt, @@ -15367,7 +15412,7 @@ type InsertWorkspaceParams struct { AutomaticUpdates AutomaticUpdates `db:"automatic_updates" json:"automatic_updates"` } -func (q *sqlQuerier) InsertWorkspace(ctx context.Context, arg InsertWorkspaceParams) (Workspace, error) { +func (q *sqlQuerier) InsertWorkspace(ctx context.Context, arg InsertWorkspaceParams) (WorkspaceTable, error) { row := q.db.QueryRowContext(ctx, insertWorkspace, arg.ID, arg.CreatedAt, @@ -15381,7 +15426,7 @@ func (q *sqlQuerier) InsertWorkspace(ctx context.Context, arg InsertWorkspacePar arg.LastUsedAt, arg.AutomaticUpdates, ) - var i Workspace + var i WorkspaceTable err := row.Scan( &i.ID, &i.CreatedAt, @@ -15445,9 +15490,9 @@ type UpdateWorkspaceParams struct { Name string `db:"name" json:"name"` } -func (q *sqlQuerier) UpdateWorkspace(ctx context.Context, arg UpdateWorkspaceParams) (Workspace, error) { +func (q *sqlQuerier) UpdateWorkspace(ctx context.Context, arg UpdateWorkspaceParams) (WorkspaceTable, error) { row := q.db.QueryRowContext(ctx, updateWorkspace, arg.ID, arg.Name) - var i Workspace + var i WorkspaceTable err := row.Scan( &i.ID, &i.CreatedAt, @@ -15558,9 +15603,9 @@ type UpdateWorkspaceDormantDeletingAtParams struct { DormantAt sql.NullTime `db:"dormant_at" json:"dormant_at"` } -func (q *sqlQuerier) UpdateWorkspaceDormantDeletingAt(ctx context.Context, arg UpdateWorkspaceDormantDeletingAtParams) (Workspace, error) { +func (q *sqlQuerier) UpdateWorkspaceDormantDeletingAt(ctx context.Context, arg UpdateWorkspaceDormantDeletingAtParams) (WorkspaceTable, error) { row := q.db.QueryRowContext(ctx, updateWorkspaceDormantDeletingAt, arg.ID, arg.DormantAt) - var i Workspace + var i WorkspaceTable err := row.Scan( &i.ID, &i.CreatedAt, @@ -15641,15 +15686,15 @@ type UpdateWorkspacesDormantDeletingAtByTemplateIDParams struct { TemplateID uuid.UUID `db:"template_id" json:"template_id"` } -func (q *sqlQuerier) UpdateWorkspacesDormantDeletingAtByTemplateID(ctx context.Context, arg UpdateWorkspacesDormantDeletingAtByTemplateIDParams) ([]Workspace, error) { +func (q *sqlQuerier) UpdateWorkspacesDormantDeletingAtByTemplateID(ctx context.Context, arg UpdateWorkspacesDormantDeletingAtByTemplateIDParams) ([]WorkspaceTable, error) { rows, err := q.db.QueryContext(ctx, updateWorkspacesDormantDeletingAtByTemplateID, arg.TimeTilDormantAutodeleteMs, arg.DormantAt, arg.TemplateID) if err != nil { return nil, err } defer rows.Close() - var items []Workspace + var items []WorkspaceTable for rows.Next() { - var i Workspace + var i WorkspaceTable if err := rows.Scan( &i.ID, &i.CreatedAt, diff --git a/coderd/database/queries/workspaces.sql b/coderd/database/queries/workspaces.sql index 42d7a5247f1b5..9d6311cb97eed 100644 --- a/coderd/database/queries/workspaces.sql +++ b/coderd/database/queries/workspaces.sql @@ -2,7 +2,7 @@ SELECT * FROM - workspaces + workspaces_expanded WHERE id = $1 LIMIT @@ -12,7 +12,7 @@ LIMIT SELECT * FROM - workspaces + workspaces_expanded as workspaces WHERE workspaces.id = ( SELECT @@ -46,12 +46,9 @@ WHERE -- name: GetWorkspaceByAgentID :one SELECT - sqlc.embed(workspaces), - templates.name as template_name + * FROM - workspaces -INNER JOIN - templates ON workspaces.template_id = templates.id + workspaces_expanded as workspaces WHERE workspaces.id = ( SELECT @@ -89,17 +86,15 @@ SELECT filtered_workspaces AS ( SELECT workspaces.*, - COALESCE(template.name, 'unknown') as template_name, latest_build.template_version_id, latest_build.template_version_name, - users.username as username, latest_build.completed_at as latest_build_completed_at, latest_build.canceled_at as latest_build_canceled_at, latest_build.error as latest_build_error, latest_build.transition as latest_build_transition, latest_build.job_status as latest_build_status FROM - workspaces + workspaces_expanded as workspaces JOIN users ON @@ -403,7 +398,7 @@ CROSS JOIN SELECT * FROM - workspaces + workspaces_expanded as workspaces WHERE owner_id = @owner_id AND deleted = @deleted diff --git a/coderd/database/sqlc.yaml b/coderd/database/sqlc.yaml index 7ef860e0b36ce..a70e45a522989 100644 --- a/coderd/database/sqlc.yaml +++ b/coderd/database/sqlc.yaml @@ -83,6 +83,8 @@ sql: template_with_name: Template workspace_build: WorkspaceBuildTable workspace_build_with_user: WorkspaceBuild + workspace: WorkspaceTable + workspaces_expanded: Workspace template_version: TemplateVersionTable template_version_with_user: TemplateVersion api_key: APIKey diff --git a/coderd/httpmw/workspaceagent.go b/coderd/httpmw/workspaceagent.go index 99889c0bae5fc..b27af7d0093a0 100644 --- a/coderd/httpmw/workspaceagent.go +++ b/coderd/httpmw/workspaceagent.go @@ -110,7 +110,7 @@ func ExtractWorkspaceAgentAndLatestBuild(opts ExtractWorkspaceAgentAndLatestBuil } //nolint:gocritic // System needs to be able to get owner roles. - roles, err := opts.DB.GetAuthorizationUserRoles(dbauthz.AsSystemRestricted(ctx), row.Workspace.OwnerID) + roles, err := opts.DB.GetAuthorizationUserRoles(dbauthz.AsSystemRestricted(ctx), row.WorkspaceTable.OwnerID) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ Message: "Internal error checking workspace agent authorization.", @@ -129,13 +129,13 @@ func ExtractWorkspaceAgentAndLatestBuild(opts ExtractWorkspaceAgentAndLatestBuil } subject := rbac.Subject{ - ID: row.Workspace.OwnerID.String(), + ID: row.WorkspaceTable.OwnerID.String(), Roles: rbac.RoleIdentifiers(roleNames), Groups: roles.Groups, Scope: rbac.WorkspaceAgentScope(rbac.WorkspaceAgentScopeParams{ - WorkspaceID: row.Workspace.ID, - OwnerID: row.Workspace.OwnerID, - TemplateID: row.Workspace.TemplateID, + WorkspaceID: row.WorkspaceTable.ID, + OwnerID: row.WorkspaceTable.OwnerID, + TemplateID: row.WorkspaceTable.TemplateID, VersionID: row.WorkspaceBuild.TemplateVersionID, }), }.WithCachedASTValue() diff --git a/coderd/prometheusmetrics/prometheusmetrics.go b/coderd/prometheusmetrics/prometheusmetrics.go index a6aec430a6b08..ebd50ff0f42ce 100644 --- a/coderd/prometheusmetrics/prometheusmetrics.go +++ b/coderd/prometheusmetrics/prometheusmetrics.go @@ -166,7 +166,7 @@ func Workspaces(ctx context.Context, logger slog.Logger, registerer prometheus.R workspaceLatestBuildStatuses.Reset() for _, w := range ws { - workspaceLatestBuildStatuses.WithLabelValues(string(w.LatestBuildStatus), w.TemplateName, w.TemplateVersionName.String, w.Username, string(w.LatestBuildTransition)).Add(1) + workspaceLatestBuildStatuses.WithLabelValues(string(w.LatestBuildStatus), w.TemplateName, w.TemplateVersionName.String, w.OwnerUsername, string(w.LatestBuildTransition)).Add(1) } } diff --git a/coderd/util/slice/slice.go b/coderd/util/slice/slice.go index 78d5e7fe61928..7317a801a089f 100644 --- a/coderd/util/slice/slice.go +++ b/coderd/util/slice/slice.go @@ -55,6 +55,17 @@ func Contains[T comparable](haystack []T, needle T) bool { }) } +// Find returns the first element that satisfies the condition. +func Find[T any](haystack []T, cond func(T) bool) (T, bool) { + for _, hay := range haystack { + if cond(hay) { + return hay, true + } + } + var empty T + return empty, false +} + // Overlap returns if the 2 sets have any overlap (element(s) in common) func Overlap[T comparable](a []T, b []T) bool { return OverlapCompare(a, b, func(a, b T) bool { diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index 4b1af869cc007..6ea631f2e7d0c 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -366,7 +366,7 @@ func (api *API) workspaceAgentLogs(rw http.ResponseWriter, r *http.Request) { return } - row, err := api.Database.GetWorkspaceByAgentID(ctx, workspaceAgent.ID) + workspace, err := api.Database.GetWorkspaceByAgentID(ctx, workspaceAgent.ID) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ Message: "Internal error fetching workspace by agent id.", @@ -374,7 +374,6 @@ func (api *API) workspaceAgentLogs(rw http.ResponseWriter, r *http.Request) { }) return } - workspace := row.Workspace api.WebsocketWaitMutex.Lock() api.WebsocketWaitGroup.Add(1) diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index 92e21b78e0756..57579ea12daad 100644 --- a/coderd/workspacebuilds.go +++ b/coderd/workspacebuilds.go @@ -72,21 +72,11 @@ func (api *API) workspaceBuild(rw http.ResponseWriter, r *http.Request) { }) return } - owner, ok := userByID(workspace.OwnerID, data.users) - if !ok { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error converting workspace build.", - Detail: "owner not found for workspace", - }) - return - } apiBuild, err := api.convertWorkspaceBuild( workspaceBuild, workspace, data.jobs[0], - owner.Username, - owner.AvatarURL, data.resources, data.metadata, data.agents, @@ -202,7 +192,6 @@ func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) { workspaceBuilds, []database.Workspace{workspace}, data.jobs, - data.users, data.resources, data.metadata, data.agents, @@ -287,21 +276,11 @@ func (api *API) workspaceBuildByBuildNumber(rw http.ResponseWriter, r *http.Requ }) return } - owner, ok := userByID(workspace.OwnerID, data.users) - if !ok { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error converting workspace build.", - Detail: "owner not found for workspace", - }) - return - } apiBuild, err := api.convertWorkspaceBuild( workspaceBuild, workspace, data.jobs[0], - owner.Username, - owner.AvatarURL, data.resources, data.metadata, data.agents, @@ -410,26 +389,6 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { api.Logger.Error(ctx, "failed to post provisioner job to pubsub", slog.Error(err)) } - users, err := api.Database.GetUsersByIDs(ctx, []uuid.UUID{ - workspace.OwnerID, - workspaceBuild.InitiatorID, - }) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error getting user.", - Detail: err.Error(), - }) - return - } - owner, exists := userByID(workspace.OwnerID, users) - if !exists { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error converting workspace build.", - Detail: "owner not found for workspace", - }) - return - } - apiBuild, err := api.convertWorkspaceBuild( *workspaceBuild, workspace, @@ -437,8 +396,6 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { ProvisionerJob: *provisionerJob, QueuePosition: 0, }, - owner.Username, - owner.AvatarURL, []database.WorkspaceResource{}, []database.WorkspaceResourceMetadatum{}, []database.WorkspaceAgent{}, @@ -674,7 +631,6 @@ func (api *API) workspaceBuildTimings(rw http.ResponseWriter, r *http.Request) { } type workspaceBuildsData struct { - users []database.User jobs []database.GetProvisionerJobsByIDsWithQueuePositionRow templateVersions []database.TemplateVersion resources []database.WorkspaceResource @@ -686,15 +642,6 @@ type workspaceBuildsData struct { } func (api *API) workspaceBuildsData(ctx context.Context, workspaces []database.Workspace, workspaceBuilds []database.WorkspaceBuild) (workspaceBuildsData, error) { - userIDs := make([]uuid.UUID, 0, len(workspaceBuilds)) - for _, workspace := range workspaces { - userIDs = append(userIDs, workspace.OwnerID) - } - users, err := api.Database.GetUsersByIDs(ctx, userIDs) - if err != nil { - return workspaceBuildsData{}, xerrors.Errorf("get users: %w", err) - } - jobIDs := make([]uuid.UUID, 0, len(workspaceBuilds)) for _, build := range workspaceBuilds { jobIDs = append(jobIDs, build.JobID) @@ -723,7 +670,6 @@ func (api *API) workspaceBuildsData(ctx context.Context, workspaces []database.W if len(resources) == 0 { return workspaceBuildsData{ - users: users, jobs: jobs, templateVersions: templateVersions, }, nil @@ -748,7 +694,6 @@ func (api *API) workspaceBuildsData(ctx context.Context, workspaces []database.W if len(resources) == 0 { return workspaceBuildsData{ - users: users, jobs: jobs, templateVersions: templateVersions, resources: resources, @@ -789,7 +734,6 @@ func (api *API) workspaceBuildsData(ctx context.Context, workspaces []database.W } return workspaceBuildsData{ - users: users, jobs: jobs, templateVersions: templateVersions, resources: resources, @@ -805,7 +749,6 @@ func (api *API) convertWorkspaceBuilds( workspaceBuilds []database.WorkspaceBuild, workspaces []database.Workspace, jobs []database.GetProvisionerJobsByIDsWithQueuePositionRow, - users []database.User, workspaceResources []database.WorkspaceResource, resourceMetadata []database.WorkspaceResourceMetadatum, resourceAgents []database.WorkspaceAgent, @@ -842,17 +785,11 @@ func (api *API) convertWorkspaceBuilds( if !exists { return nil, xerrors.New("template version not found") } - owner, exists := userByID(workspace.OwnerID, users) - if !exists { - return nil, xerrors.Errorf("owner not found for workspace: %q", workspace.Name) - } apiBuild, err := api.convertWorkspaceBuild( build, workspace, job, - owner.Username, - owner.AvatarURL, workspaceResources, resourceMetadata, resourceAgents, @@ -875,7 +812,6 @@ func (api *API) convertWorkspaceBuild( build database.WorkspaceBuild, workspace database.Workspace, job database.GetProvisionerJobsByIDsWithQueuePositionRow, - username, avatarURL string, workspaceResources []database.WorkspaceResource, resourceMetadata []database.WorkspaceResourceMetadatum, resourceAgents []database.WorkspaceAgent, @@ -931,7 +867,7 @@ func (api *API) convertWorkspaceBuild( scripts := scriptsByAgentID[agent.ID] logSources := logSourcesByAgentID[agent.ID] apiAgent, err := db2sdk.WorkspaceAgent( - api.DERPMap(), *api.TailnetCoordinator.Load(), agent, db2sdk.Apps(apps, agent, username, workspace), convertScripts(scripts), convertLogSources(logSources), api.AgentInactiveDisconnectTimeout, + api.DERPMap(), *api.TailnetCoordinator.Load(), agent, db2sdk.Apps(apps, agent, workspace.OwnerUsername, workspace), convertScripts(scripts), convertLogSources(logSources), api.AgentInactiveDisconnectTimeout, api.DeploymentValues.AgentFallbackTroubleshootingURL.String(), ) if err != nil { @@ -958,8 +894,8 @@ func (api *API) convertWorkspaceBuild( CreatedAt: build.CreatedAt, UpdatedAt: build.UpdatedAt, WorkspaceOwnerID: workspace.OwnerID, - WorkspaceOwnerName: username, - WorkspaceOwnerAvatarURL: avatarURL, + WorkspaceOwnerName: workspace.OwnerUsername, + WorkspaceOwnerAvatarURL: workspace.OwnerAvatarUrl, WorkspaceID: build.WorkspaceID, WorkspaceName: workspace.Name, TemplateVersionID: build.TemplateVersionID, diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 2407130ea38e4..a901209094984 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -99,22 +99,12 @@ func (api *API) workspace(rw http.ResponseWriter, r *http.Request) { httpapi.Forbidden(rw) return } - owner, ok := userByID(workspace.OwnerID, data.users) - if !ok { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching workspace resources.", - Detail: "unable to find workspace owner's username", - }) - return - } w, err := convertWorkspace( apiKey.UserID, workspace, data.builds[0], data.templates[0], - owner.Username, - owner.AvatarURL, api.Options.AllowWorkspaceRenames, ) if err != nil { @@ -307,21 +297,12 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request) httpapi.ResourceNotFound(rw) return } - owner, ok := userByID(workspace.OwnerID, data.users) - if !ok { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching workspace resources.", - Detail: "unable to find workspace owner's username", - }) - return - } + w, err := convertWorkspace( apiKey.UserID, workspace, data.builds[0], data.templates[0], - owner.Username, - owner.AvatarURL, api.Options.AllowWorkspaceRenames, ) if err != nil { @@ -364,7 +345,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req } ) - aReq, commitAudit := audit.InitRequest[database.Workspace](rw, &audit.RequestParams{ + aReq, commitAudit := audit.InitRequest[database.WorkspaceTable](rw, &audit.RequestParams{ Audit: *auditor, Log: api.Logger, Request: r, @@ -413,7 +394,7 @@ func (api *API) postUserWorkspaces(rw http.ResponseWriter, r *http.Request) { user = httpmw.UserParam(r) ) - aReq, commitAudit := audit.InitRequest[database.Workspace](rw, &audit.RequestParams{ + aReq, commitAudit := audit.InitRequest[database.WorkspaceTable](rw, &audit.RequestParams{ Audit: *auditor, Log: api.Logger, Request: r, @@ -446,7 +427,7 @@ type workspaceOwner struct { func createWorkspace( ctx context.Context, - auditReq *audit.Request[database.Workspace], + auditReq *audit.Request[database.WorkspaceTable], initiatorID uuid.UUID, api *API, owner workspaceOwner, @@ -627,7 +608,7 @@ func createWorkspace( err = api.Database.InTx(func(db database.Store) error { now := dbtime.Now() // Workspaces are created without any versions. - workspace, err = db.InsertWorkspace(ctx, database.InsertWorkspaceParams{ + minimumWorkspace, err := db.InsertWorkspace(ctx, database.InsertWorkspaceParams{ ID: uuid.New(), CreatedAt: now, UpdatedAt: now, @@ -646,6 +627,14 @@ func createWorkspace( return xerrors.Errorf("insert workspace: %w", err) } + // 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) + if err != nil { + return xerrors.Errorf("get workspace by ID: %w", err) + } + builder := wsbuilder.New(workspace, database.WorkspaceTransitionStart). Reason(database.BuildReasonInitiator). Initiator(initiatorID). @@ -685,7 +674,7 @@ func createWorkspace( // Client probably doesn't care about this error, so just log it. api.Logger.Error(ctx, "failed to post provisioner job to pubsub", slog.Error(err)) } - auditReq.New = workspace + auditReq.New = workspace.WorkspaceTable() api.Telemetry.Report(&telemetry.Snapshot{ Workspaces: []telemetry.Workspace{telemetry.ConvertWorkspace(workspace)}, @@ -699,8 +688,6 @@ func createWorkspace( ProvisionerJob: *provisionerJob, QueuePosition: 0, }, - owner.Username, - owner.AvatarURL, []database.WorkspaceResource{}, []database.WorkspaceResourceMetadatum{}, []database.WorkspaceAgent{}, @@ -722,8 +709,6 @@ func createWorkspace( workspace, apiBuild, template, - owner.Username, - owner.AvatarURL, api.Options.AllowWorkspaceRenames, ) if err != nil { @@ -750,7 +735,7 @@ func (api *API) patchWorkspace(rw http.ResponseWriter, r *http.Request) { ctx = r.Context() workspace = httpmw.WorkspaceParam(r) auditor = api.Auditor.Load() - aReq, commitAudit = audit.InitRequest[database.Workspace](rw, &audit.RequestParams{ + aReq, commitAudit = audit.InitRequest[database.WorkspaceTable](rw, &audit.RequestParams{ Audit: *auditor, Log: api.Logger, Request: r, @@ -759,7 +744,7 @@ func (api *API) patchWorkspace(rw http.ResponseWriter, r *http.Request) { }) ) defer commitAudit() - aReq.Old = workspace + aReq.Old = workspace.WorkspaceTable() var req codersdk.UpdateWorkspaceRequest if !httpapi.Read(ctx, rw, r, &req) { @@ -767,7 +752,7 @@ func (api *API) patchWorkspace(rw http.ResponseWriter, r *http.Request) { } if req.Name == "" || req.Name == workspace.Name { - aReq.New = workspace + aReq.New = workspace.WorkspaceTable() // Nothing changed, optionally this could be an error. rw.WriteHeader(http.StatusNoContent) return @@ -822,8 +807,8 @@ func (api *API) patchWorkspace(rw http.ResponseWriter, r *http.Request) { } api.publishWorkspaceUpdate(ctx, workspace.ID) - aReq.New = newWorkspace + rw.WriteHeader(http.StatusNoContent) } @@ -841,7 +826,7 @@ func (api *API) putWorkspaceAutostart(rw http.ResponseWriter, r *http.Request) { ctx = r.Context() workspace = httpmw.WorkspaceParam(r) auditor = api.Auditor.Load() - aReq, commitAudit = audit.InitRequest[database.Workspace](rw, &audit.RequestParams{ + aReq, commitAudit = audit.InitRequest[database.WorkspaceTable](rw, &audit.RequestParams{ Audit: *auditor, Log: api.Logger, Request: r, @@ -850,7 +835,7 @@ func (api *API) putWorkspaceAutostart(rw http.ResponseWriter, r *http.Request) { }) ) defer commitAudit() - aReq.Old = workspace + aReq.Old = workspace.WorkspaceTable() var req codersdk.UpdateWorkspaceAutostartRequest if !httpapi.Read(ctx, rw, r, &req) { @@ -897,7 +882,7 @@ func (api *API) putWorkspaceAutostart(rw http.ResponseWriter, r *http.Request) { newWorkspace := workspace newWorkspace.AutostartSchedule = dbSched - aReq.New = newWorkspace + aReq.New = newWorkspace.WorkspaceTable() rw.WriteHeader(http.StatusNoContent) } @@ -916,7 +901,7 @@ func (api *API) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) { ctx = r.Context() workspace = httpmw.WorkspaceParam(r) auditor = api.Auditor.Load() - aReq, commitAudit = audit.InitRequest[database.Workspace](rw, &audit.RequestParams{ + aReq, commitAudit = audit.InitRequest[database.WorkspaceTable](rw, &audit.RequestParams{ Audit: *auditor, Log: api.Logger, Request: r, @@ -925,7 +910,7 @@ func (api *API) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) { }) ) defer commitAudit() - aReq.Old = workspace + aReq.Old = workspace.WorkspaceTable() var req codersdk.UpdateWorkspaceTTLRequest if !httpapi.Read(ctx, rw, r, &req) { @@ -977,7 +962,7 @@ func (api *API) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) { newWorkspace := workspace newWorkspace.Ttl = dbTTL - aReq.New = newWorkspace + aReq.New = newWorkspace.WorkspaceTable() rw.WriteHeader(http.StatusNoContent) } @@ -995,19 +980,18 @@ func (api *API) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) { func (api *API) putWorkspaceDormant(rw http.ResponseWriter, r *http.Request) { var ( ctx = r.Context() - workspace = httpmw.WorkspaceParam(r) + oldWorkspace = httpmw.WorkspaceParam(r) apiKey = httpmw.APIKey(r) - oldWorkspace = workspace auditor = api.Auditor.Load() - aReq, commitAudit = audit.InitRequest[database.Workspace](rw, &audit.RequestParams{ + aReq, commitAudit = audit.InitRequest[database.WorkspaceTable](rw, &audit.RequestParams{ Audit: *auditor, Log: api.Logger, Request: r, Action: database.AuditActionWrite, - OrganizationID: workspace.OrganizationID, + OrganizationID: oldWorkspace.OrganizationID, }) ) - aReq.Old = oldWorkspace + aReq.Old = oldWorkspace.WorkspaceTable() defer commitAudit() var req codersdk.UpdateWorkspaceDormancy @@ -1016,7 +1000,7 @@ func (api *API) putWorkspaceDormant(rw http.ResponseWriter, r *http.Request) { } // If the workspace is already in the desired state do nothing! - if workspace.DormantAt.Valid == req.Dormant { + if oldWorkspace.DormantAt.Valid == req.Dormant { rw.WriteHeader(http.StatusNotModified) return } @@ -1028,8 +1012,8 @@ func (api *API) putWorkspaceDormant(rw http.ResponseWriter, r *http.Request) { dormantAt.Time = dbtime.Now() } - workspace, err := api.Database.UpdateWorkspaceDormantDeletingAt(ctx, database.UpdateWorkspaceDormantDeletingAtParams{ - ID: workspace.ID, + newWorkspace, err := api.Database.UpdateWorkspaceDormantDeletingAt(ctx, database.UpdateWorkspaceDormantDeletingAtParams{ + ID: oldWorkspace.ID, DormantAt: dormantAt, }) if err != nil { @@ -1041,26 +1025,26 @@ func (api *API) putWorkspaceDormant(rw http.ResponseWriter, r *http.Request) { } // We don't need to notify the owner if they are the one making the request. - if req.Dormant && apiKey.UserID != workspace.OwnerID { + if req.Dormant && apiKey.UserID != newWorkspace.OwnerID { initiator, initiatorErr := api.Database.GetUserByID(ctx, apiKey.UserID) if initiatorErr != nil { api.Logger.Warn( ctx, "failed to fetch the user that marked the workspace as dormant", slog.Error(err), - slog.F("workspace_id", workspace.ID), + slog.F("workspace_id", newWorkspace.ID), slog.F("user_id", apiKey.UserID), ) } - tmpl, tmplErr := api.Database.GetTemplateByID(ctx, workspace.TemplateID) + tmpl, tmplErr := api.Database.GetTemplateByID(ctx, newWorkspace.TemplateID) if tmplErr != nil { api.Logger.Warn( ctx, "failed to fetch the template of the workspace marked as dormant", slog.Error(err), - slog.F("workspace_id", workspace.ID), - slog.F("template_id", workspace.TemplateID), + slog.F("workspace_id", newWorkspace.ID), + slog.F("template_id", newWorkspace.TemplateID), ) } @@ -1068,18 +1052,18 @@ func (api *API) putWorkspaceDormant(rw http.ResponseWriter, r *http.Request) { dormantTime := dbtime.Now().Add(time.Duration(tmpl.TimeTilDormant)) _, err = api.NotificationsEnqueuer.Enqueue( ctx, - workspace.OwnerID, + newWorkspace.OwnerID, notifications.TemplateWorkspaceDormant, map[string]string{ - "name": workspace.Name, + "name": newWorkspace.Name, "reason": "a " + initiator.Username + " request", "timeTilDormant": humanize.Time(dormantTime), }, "api", - workspace.ID, - workspace.OwnerID, - workspace.TemplateID, - workspace.OrganizationID, + newWorkspace.ID, + newWorkspace.OwnerID, + newWorkspace.TemplateID, + newWorkspace.OrganizationID, ) if err != nil { api.Logger.Warn(ctx, "failed to notify of workspace marked as dormant", slog.Error(err)) @@ -1087,37 +1071,40 @@ func (api *API) putWorkspaceDormant(rw http.ResponseWriter, r *http.Request) { } } - data, err := api.workspaceData(ctx, []database.Workspace{workspace}) + // We have to refetch the workspace to get the joined in fields. + workspace, err := api.Database.GetWorkspaceByID(ctx, newWorkspace.ID) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching workspace resources.", + Message: "Internal error fetching workspace.", Detail: err.Error(), }) return } - owner, ok := userByID(workspace.OwnerID, data.users) - if !ok { + + data, err := api.workspaceData(ctx, []database.Workspace{workspace}) + if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ Message: "Internal error fetching workspace resources.", - Detail: "unable to find workspace owner's username", + Detail: err.Error(), }) return } + // TODO: This is a strange error since it occurs after the mutatation. + // An example of why we should join in fields to prevent this forbidden error + // from being sent, when the action did succeed. if len(data.templates) == 0 { httpapi.Forbidden(rw) return } - aReq.New = workspace + aReq.New = newWorkspace w, err := convertWorkspace( apiKey.UserID, workspace, data.builds[0], data.templates[0], - owner.Username, - owner.AvatarURL, api.Options.AllowWorkspaceRenames, ) if err != nil { @@ -1371,7 +1358,7 @@ func (api *API) putFavoriteWorkspace(rw http.ResponseWriter, r *http.Request) { return } - aReq, commitAudit := audit.InitRequest[database.Workspace](rw, &audit.RequestParams{ + aReq, commitAudit := audit.InitRequest[database.WorkspaceTable](rw, &audit.RequestParams{ Audit: *auditor, Log: api.Logger, Request: r, @@ -1379,7 +1366,7 @@ func (api *API) putFavoriteWorkspace(rw http.ResponseWriter, r *http.Request) { OrganizationID: workspace.OrganizationID, }) defer commitAudit() - aReq.Old = workspace + aReq.Old = workspace.WorkspaceTable() err := api.Database.FavoriteWorkspace(ctx, workspace.ID) if err != nil { @@ -1390,7 +1377,7 @@ func (api *API) putFavoriteWorkspace(rw http.ResponseWriter, r *http.Request) { return } - aReq.New = workspace + aReq.New = workspace.WorkspaceTable() aReq.New.Favorite = true rw.WriteHeader(http.StatusNoContent) @@ -1418,7 +1405,7 @@ func (api *API) deleteFavoriteWorkspace(rw http.ResponseWriter, r *http.Request) return } - aReq, commitAudit := audit.InitRequest[database.Workspace](rw, &audit.RequestParams{ + aReq, commitAudit := audit.InitRequest[database.WorkspaceTable](rw, &audit.RequestParams{ Audit: *auditor, Log: api.Logger, Request: r, @@ -1427,7 +1414,7 @@ func (api *API) deleteFavoriteWorkspace(rw http.ResponseWriter, r *http.Request) }) defer commitAudit() - aReq.Old = workspace + aReq.Old = workspace.WorkspaceTable() err := api.Database.UnfavoriteWorkspace(ctx, workspace.ID) if err != nil { @@ -1437,7 +1424,7 @@ func (api *API) deleteFavoriteWorkspace(rw http.ResponseWriter, r *http.Request) }) return } - aReq.New = workspace + aReq.New = workspace.WorkspaceTable() aReq.New.Favorite = false rw.WriteHeader(http.StatusNoContent) @@ -1457,7 +1444,7 @@ func (api *API) putWorkspaceAutoupdates(rw http.ResponseWriter, r *http.Request) ctx = r.Context() workspace = httpmw.WorkspaceParam(r) auditor = api.Auditor.Load() - aReq, commitAudit = audit.InitRequest[database.Workspace](rw, &audit.RequestParams{ + aReq, commitAudit = audit.InitRequest[database.WorkspaceTable](rw, &audit.RequestParams{ Audit: *auditor, Log: api.Logger, Request: r, @@ -1466,7 +1453,7 @@ func (api *API) putWorkspaceAutoupdates(rw http.ResponseWriter, r *http.Request) }) ) defer commitAudit() - aReq.Old = workspace + aReq.Old = workspace.WorkspaceTable() var req codersdk.UpdateWorkspaceAutomaticUpdatesRequest if !httpapi.Read(ctx, rw, r, &req) { @@ -1499,7 +1486,7 @@ func (api *API) putWorkspaceAutoupdates(rw http.ResponseWriter, r *http.Request) newWorkspace := workspace newWorkspace.AutomaticUpdates = database.AutomaticUpdates(req.AutomaticUpdates) - aReq.New = newWorkspace + aReq.New = newWorkspace.WorkspaceTable() rw.WriteHeader(http.StatusNoContent) } @@ -1658,25 +1645,11 @@ func (api *API) watchWorkspace(rw http.ResponseWriter, r *http.Request) { return } - owner, ok := userByID(workspace.OwnerID, data.users) - if !ok { - _ = sendEvent(ctx, codersdk.ServerSentEvent{ - Type: codersdk.ServerSentEventTypeError, - Data: codersdk.Response{ - Message: "Internal error fetching workspace resources.", - Detail: "unable to find workspace owner's username", - }, - }) - return - } - w, err := convertWorkspace( apiKey.UserID, workspace, data.builds[0], data.templates[0], - owner.Username, - owner.AvatarURL, api.Options.AllowWorkspaceRenames, ) if err != nil { @@ -1778,7 +1751,6 @@ func (api *API) workspaceTimings(rw http.ResponseWriter, r *http.Request) { type workspaceData struct { templates []database.Template builds []codersdk.WorkspaceBuild - users []database.User allowRenames bool } @@ -1817,7 +1789,6 @@ func (api *API) workspaceData(ctx context.Context, workspaces []database.Workspa builds, workspaces, data.jobs, - data.users, data.resources, data.metadata, data.agents, @@ -1833,7 +1804,6 @@ func (api *API) workspaceData(ctx context.Context, workspaces []database.Workspa return workspaceData{ templates: templates, builds: apiBuilds, - users: data.users, allowRenames: api.Options.AllowWorkspaceRenames, }, nil } @@ -1847,10 +1817,6 @@ func convertWorkspaces(requesterID uuid.UUID, workspaces []database.Workspace, d for _, template := range data.templates { templateByID[template.ID] = template } - userByID := map[uuid.UUID]database.User{} - for _, user := range data.users { - userByID[user.ID] = user - } apiWorkspaces := make([]codersdk.Workspace, 0, len(workspaces)) for _, workspace := range workspaces { @@ -1867,18 +1833,12 @@ func convertWorkspaces(requesterID uuid.UUID, workspaces []database.Workspace, d if !exists { continue } - owner, exists := userByID[workspace.OwnerID] - if !exists { - continue - } w, err := convertWorkspace( requesterID, workspace, build, template, - owner.Username, - owner.AvatarURL, data.allowRenames, ) if err != nil { @@ -1895,8 +1855,6 @@ func convertWorkspace( workspace database.Workspace, workspaceBuild codersdk.WorkspaceBuild, template database.Template, - username string, - avatarURL string, allowRenames bool, ) (codersdk.Workspace, error) { if requesterID == uuid.Nil { @@ -1941,15 +1899,15 @@ func convertWorkspace( CreatedAt: workspace.CreatedAt, UpdatedAt: workspace.UpdatedAt, OwnerID: workspace.OwnerID, - OwnerName: username, - OwnerAvatarURL: avatarURL, + OwnerName: workspace.OwnerUsername, + OwnerAvatarURL: workspace.OwnerAvatarUrl, OrganizationID: workspace.OrganizationID, - OrganizationName: template.OrganizationName, + OrganizationName: workspace.OrganizationName, TemplateID: workspace.TemplateID, LatestBuild: workspaceBuild, - TemplateName: template.Name, - TemplateIcon: template.Icon, - TemplateDisplayName: template.DisplayName, + TemplateName: workspace.TemplateName, + TemplateIcon: workspace.TemplateIcon, + TemplateDisplayName: workspace.TemplateDisplayName, TemplateAllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs, TemplateActiveVersionID: template.ActiveVersionID, TemplateRequireActiveVersion: template.RequireActiveVersion, From 15d24fb0cfd33c6993cc327ffb8063fc7cb019c4 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 16 Oct 2024 16:42:35 -0500 Subject: [PATCH 02/23] random text got added --- coderd/activitybump_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/activitybump_test.go b/coderd/activitybump_test.go index aa0ad925c2357..60aec23475885 100644 --- a/coderd/activitybump_test.go +++ b/coderd/activitybump_test.go @@ -199,7 +199,7 @@ func TestWorkspaceActivityBump(t *testing.T) { t.Parallel() client, workspace, assertBumped := setupActivityTest(t) - Access - Control - Allow - Origin + resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) conn, err := workspacesdk.New(client). DialAgent(ctx, resources[0].Agents[0].ID, &workspacesdk.DialAgentOptions{ From a3ea2bddb0b02cca075d0bd4bcfb0f645f10849b Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 16 Oct 2024 17:21:49 -0500 Subject: [PATCH 03/23] add unit test to verify subset of fields --- coderd/database/dbgen/dbgen.go | 2 +- coderd/database/gentest/models_test.go | 14 ++ ...l => 000266_workspace_with_names.down.sql} | 0 ...sql => 000266_workspace_with_names.up.sql} | 0 coderd/database/modelqueries_internal_test.go | 67 +-------- testutil/reflect.go | 139 ++++++++++++++++++ 6 files changed, 160 insertions(+), 62 deletions(-) rename coderd/database/migrations/{000262_workspace_with_names.down.sql => 000266_workspace_with_names.down.sql} (100%) rename coderd/database/migrations/{000262_workspace_with_names.up.sql => 000266_workspace_with_names.up.sql} (100%) create mode 100644 testutil/reflect.go diff --git a/coderd/database/dbgen/dbgen.go b/coderd/database/dbgen/dbgen.go index a8ecabe752011..255c62f82aef2 100644 --- a/coderd/database/dbgen/dbgen.go +++ b/coderd/database/dbgen/dbgen.go @@ -232,7 +232,7 @@ func WorkspaceAgentScriptTiming(t testing.TB, db database.Store, orig database.W return timing } -func Workspace(t testing.TB, db database.Store, orig database.Workspace) database.Workspace { +func Workspace(t testing.TB, db database.Store, orig database.WorkspaceTable) database.WorkspaceTable { t.Helper() workspace, err := db.InsertWorkspace(genCtx, database.InsertWorkspaceParams{ diff --git a/coderd/database/gentest/models_test.go b/coderd/database/gentest/models_test.go index c1d2ea4999668..7cd54224cfaf2 100644 --- a/coderd/database/gentest/models_test.go +++ b/coderd/database/gentest/models_test.go @@ -65,6 +65,20 @@ func TestViewSubsetWorkspaceBuild(t *testing.T) { } } +// TestViewSubsetWorkspace ensures WorkspaceTable is a subset of Workspace +func TestViewSubsetWorkspace(t *testing.T) { + t.Parallel() + table := reflect.TypeOf(database.WorkspaceTable{}) + joined := reflect.TypeOf(database.Workspace{}) + + tableFields := allFields(table) + joinedFields := allFields(joined) + if !assert.Subset(t, fieldNames(joinedFields), fieldNames(tableFields), "table is not subset") { + t.Log("Some fields were added to the Workspace Table without updating the 'workspaces_expanded' view.") + t.Log("See migration 000262_workspace_with_names.up.sql to create the view.") + } +} + func fieldNames(fields []reflect.StructField) []string { names := make([]string, len(fields)) for i, field := range fields { diff --git a/coderd/database/migrations/000262_workspace_with_names.down.sql b/coderd/database/migrations/000266_workspace_with_names.down.sql similarity index 100% rename from coderd/database/migrations/000262_workspace_with_names.down.sql rename to coderd/database/migrations/000266_workspace_with_names.down.sql diff --git a/coderd/database/migrations/000262_workspace_with_names.up.sql b/coderd/database/migrations/000266_workspace_with_names.up.sql similarity index 100% rename from coderd/database/migrations/000262_workspace_with_names.up.sql rename to coderd/database/migrations/000266_workspace_with_names.up.sql diff --git a/coderd/database/modelqueries_internal_test.go b/coderd/database/modelqueries_internal_test.go index 773dfb9eea82d..2d15b91d297b1 100644 --- a/coderd/database/modelqueries_internal_test.go +++ b/coderd/database/modelqueries_internal_test.go @@ -2,10 +2,11 @@ package database import ( "fmt" - "reflect" "testing" "github.com/stretchr/testify/require" + + "github.com/coder/coder/v2/testutil" ) func TestIsAuthorizedQuery(t *testing.T) { @@ -22,68 +23,12 @@ func TestWorkspaceTableConvert(t *testing.T) { t.Parallel() var workspace Workspace - err := populateStruct(&workspace) + err := testutil.PopulateStruct(&workspace, nil) require.NoError(t, err) -} - -func populateStruct(s interface{}) error { - v := reflect.ValueOf(s) - if v.Kind() != reflect.Ptr || v.IsNil() { - return fmt.Errorf("s must be a non-nil pointer") - } - - v = v.Elem() - if v.Kind() != reflect.Struct { - return fmt.Errorf("s must be a pointer to a struct") - } - - t := v.Type() - for i := 0; i < t.NumField(); i++ { - field := t.Field(i) - fieldName := field.Name - - fieldValue := v.Field(i) - if !fieldValue.CanSet() { - continue // Skip if field is unexported - } + workspace.WorkspaceTable() + require.JSONEq(t) - switch fieldValue.Kind() { - case reflect.Struct: - if err := populateStruct(fieldValue.Addr().Interface()); err != nil { - return fmt.Errorf("%s : %w", fieldName, err) - } - case reflect.String: - fieldValue.SetString("foo") - case reflect.Invalid: - case reflect.Bool: - case reflect.Int: - case reflect.Int8: - case reflect.Int16: - case reflect.Int32: - case reflect.Int64: - case reflect.Uint: - case reflect.Uint8: - case reflect.Uint16: - case reflect.Uint32: - case reflect.Uint64: - case reflect.Uintptr: - case reflect.Float32: - case reflect.Float64: - case reflect.Complex64: - case reflect.Complex128: - case reflect.Array: - case reflect.Chan: - case reflect.Func: - case reflect.Interface: - case reflect.Map: - case reflect.Pointer: - case reflect.Slice: - case reflect.UnsafePointer: - default: - return fmt.Errorf("unsupported kind %s", fieldValue.Kind()) - } - } + fmt.Println(workspace) - return nil } diff --git a/testutil/reflect.go b/testutil/reflect.go new file mode 100644 index 0000000000000..b1e9b37899fda --- /dev/null +++ b/testutil/reflect.go @@ -0,0 +1,139 @@ +package testutil + +import ( + "fmt" + "reflect" + "time" +) + +type Random struct { + String func() string + Bool func() bool + Int func() int64 + Uint func() uint64 + Float func() float64 + Complex func() complex128 +} + +func NewRandom() *Random { + // Guaranteed to be random... + return &Random{ + String: func() string { return "foo" }, + Bool: func() bool { return true }, + Int: func() int64 { return 500 }, + Uint: func() uint64 { return 126 }, + Float: func() float64 { return 3.14 }, + Complex: func() complex128 { return 6.24 }, + } +} + +// PopulateStruct does a best effort to populate a struct with random values. +func PopulateStruct(s interface{}, r *Random) error { + if r == nil { + r = NewRandom() + } + + v := reflect.ValueOf(s) + if v.Kind() != reflect.Ptr || v.IsNil() { + return fmt.Errorf("s must be a non-nil pointer") + } + + v = v.Elem() + if v.Kind() != reflect.Struct { + return fmt.Errorf("s must be a pointer to a struct") + } + + t := v.Type() + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + fieldName := field.Name + + fieldValue := v.Field(i) + if !fieldValue.CanSet() { + continue // Skip if field is unexported + } + + nv, err := populateValue(fieldValue, r) + if err != nil { + return fmt.Errorf("%s : %w", fieldName, err) + } + v.Field(i).Set(nv) + } + + return nil +} + +func populateValue(v reflect.Value, r *Random) (reflect.Value, error) { + var err error + + // Handle some special cases + switch v.Type() { + case reflect.TypeOf(time.Time{}): + v.Set(reflect.ValueOf(time.Date(2020, 5, 2, 5, 19, 21, 30, time.UTC))) + return v, nil + } + + switch v.Kind() { + case reflect.Struct: + if err := PopulateStruct(v.Addr().Interface(), r); err != nil { + return v, err + } + case reflect.String: + v.SetString(r.String()) + case reflect.Bool: + v.SetBool(true) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + v.SetInt(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + v.SetUint(r.Uint()) + case reflect.Float32, reflect.Float64: + v.SetFloat(r.Float()) + case reflect.Complex64, reflect.Complex128: + v.SetComplex(r.Complex()) + case reflect.Array: + for i := 0; i < v.Len(); i++ { + nv, err := populateValue(v.Index(i), r) + if err != nil { + return v, fmt.Errorf("array index %d : %w", i, err) + } + v.Index(i).Set(nv) + } + case reflect.Map: + m := reflect.MakeMap(v.Type()) + + // Set a value in the map + k := reflect.New(v.Type().Key()) + kv := reflect.New(v.Type().Elem()) + k, err = populateValue(k, r) + if err != nil { + return v, fmt.Errorf("map key : %w", err) + } + kv, err = populateValue(kv, r) + if err != nil { + return v, fmt.Errorf("map value : %w", err) + } + + m.SetMapIndex(k, kv) + return m, nil + case reflect.Pointer: + return populateValue(v.Elem(), r) + case reflect.Slice: + s := reflect.MakeSlice(v.Type(), 2, 2) + sv, err := populateValue(reflect.New(v.Type().Elem()), r) + if err != nil { + return v, fmt.Errorf("slice value : %w", err) + } + + s.Index(0).Set(sv) + s.Index(1).Set(sv) + //reflect.AppendSlice(s, sv) + + return s, nil + case reflect.Uintptr, reflect.UnsafePointer, reflect.Chan, reflect.Func, reflect.Interface: + // Unsupported + return v, fmt.Errorf("%s is not supported", v.Kind()) + default: + return v, fmt.Errorf("unsupported kind %s", v.Kind()) + } + return v, nil +} From d3bebaed03397f5a839e5357fb1393be2b451a13 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 16 Oct 2024 17:22:20 -0500 Subject: [PATCH 04/23] remove unused --- coderd/database/modelqueries_internal_test.go | 19 --- testutil/reflect.go | 139 ------------------ 2 files changed, 158 deletions(-) delete mode 100644 testutil/reflect.go diff --git a/coderd/database/modelqueries_internal_test.go b/coderd/database/modelqueries_internal_test.go index 2d15b91d297b1..4977120e88135 100644 --- a/coderd/database/modelqueries_internal_test.go +++ b/coderd/database/modelqueries_internal_test.go @@ -1,12 +1,9 @@ package database import ( - "fmt" "testing" "github.com/stretchr/testify/require" - - "github.com/coder/coder/v2/testutil" ) func TestIsAuthorizedQuery(t *testing.T) { @@ -16,19 +13,3 @@ func TestIsAuthorizedQuery(t *testing.T) { _, err := insertAuthorizedFilter(query, "") require.ErrorContains(t, err, "does not contain authorized replace string", "ensure replace string") } - -// TestWorkspaceTableConvert verifies all workspace fields are converted -// when reducing a `Workspace` to a `WorkspaceTable`. -func TestWorkspaceTableConvert(t *testing.T) { - t.Parallel() - - var workspace Workspace - err := testutil.PopulateStruct(&workspace, nil) - require.NoError(t, err) - - workspace.WorkspaceTable() - require.JSONEq(t) - - fmt.Println(workspace) - -} diff --git a/testutil/reflect.go b/testutil/reflect.go deleted file mode 100644 index b1e9b37899fda..0000000000000 --- a/testutil/reflect.go +++ /dev/null @@ -1,139 +0,0 @@ -package testutil - -import ( - "fmt" - "reflect" - "time" -) - -type Random struct { - String func() string - Bool func() bool - Int func() int64 - Uint func() uint64 - Float func() float64 - Complex func() complex128 -} - -func NewRandom() *Random { - // Guaranteed to be random... - return &Random{ - String: func() string { return "foo" }, - Bool: func() bool { return true }, - Int: func() int64 { return 500 }, - Uint: func() uint64 { return 126 }, - Float: func() float64 { return 3.14 }, - Complex: func() complex128 { return 6.24 }, - } -} - -// PopulateStruct does a best effort to populate a struct with random values. -func PopulateStruct(s interface{}, r *Random) error { - if r == nil { - r = NewRandom() - } - - v := reflect.ValueOf(s) - if v.Kind() != reflect.Ptr || v.IsNil() { - return fmt.Errorf("s must be a non-nil pointer") - } - - v = v.Elem() - if v.Kind() != reflect.Struct { - return fmt.Errorf("s must be a pointer to a struct") - } - - t := v.Type() - for i := 0; i < t.NumField(); i++ { - field := t.Field(i) - fieldName := field.Name - - fieldValue := v.Field(i) - if !fieldValue.CanSet() { - continue // Skip if field is unexported - } - - nv, err := populateValue(fieldValue, r) - if err != nil { - return fmt.Errorf("%s : %w", fieldName, err) - } - v.Field(i).Set(nv) - } - - return nil -} - -func populateValue(v reflect.Value, r *Random) (reflect.Value, error) { - var err error - - // Handle some special cases - switch v.Type() { - case reflect.TypeOf(time.Time{}): - v.Set(reflect.ValueOf(time.Date(2020, 5, 2, 5, 19, 21, 30, time.UTC))) - return v, nil - } - - switch v.Kind() { - case reflect.Struct: - if err := PopulateStruct(v.Addr().Interface(), r); err != nil { - return v, err - } - case reflect.String: - v.SetString(r.String()) - case reflect.Bool: - v.SetBool(true) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - v.SetInt(r.Int()) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - v.SetUint(r.Uint()) - case reflect.Float32, reflect.Float64: - v.SetFloat(r.Float()) - case reflect.Complex64, reflect.Complex128: - v.SetComplex(r.Complex()) - case reflect.Array: - for i := 0; i < v.Len(); i++ { - nv, err := populateValue(v.Index(i), r) - if err != nil { - return v, fmt.Errorf("array index %d : %w", i, err) - } - v.Index(i).Set(nv) - } - case reflect.Map: - m := reflect.MakeMap(v.Type()) - - // Set a value in the map - k := reflect.New(v.Type().Key()) - kv := reflect.New(v.Type().Elem()) - k, err = populateValue(k, r) - if err != nil { - return v, fmt.Errorf("map key : %w", err) - } - kv, err = populateValue(kv, r) - if err != nil { - return v, fmt.Errorf("map value : %w", err) - } - - m.SetMapIndex(k, kv) - return m, nil - case reflect.Pointer: - return populateValue(v.Elem(), r) - case reflect.Slice: - s := reflect.MakeSlice(v.Type(), 2, 2) - sv, err := populateValue(reflect.New(v.Type().Elem()), r) - if err != nil { - return v, fmt.Errorf("slice value : %w", err) - } - - s.Index(0).Set(sv) - s.Index(1).Set(sv) - //reflect.AppendSlice(s, sv) - - return s, nil - case reflect.Uintptr, reflect.UnsafePointer, reflect.Chan, reflect.Func, reflect.Interface: - // Unsupported - return v, fmt.Errorf("%s is not supported", v.Kind()) - default: - return v, fmt.Errorf("unsupported kind %s", v.Kind()) - } - return v, nil -} From ba8077dacd5b170c0717b3de8f19495954ddf04b Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 16 Oct 2024 17:22:40 -0500 Subject: [PATCH 05/23] Revert "remove unused" This reverts commit e23704cb2b5d80c8f13ee82c293880e2721736c7. --- coderd/database/modelqueries_internal_test.go | 19 +++ testutil/reflect.go | 139 ++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 testutil/reflect.go diff --git a/coderd/database/modelqueries_internal_test.go b/coderd/database/modelqueries_internal_test.go index 4977120e88135..2d15b91d297b1 100644 --- a/coderd/database/modelqueries_internal_test.go +++ b/coderd/database/modelqueries_internal_test.go @@ -1,9 +1,12 @@ package database import ( + "fmt" "testing" "github.com/stretchr/testify/require" + + "github.com/coder/coder/v2/testutil" ) func TestIsAuthorizedQuery(t *testing.T) { @@ -13,3 +16,19 @@ func TestIsAuthorizedQuery(t *testing.T) { _, err := insertAuthorizedFilter(query, "") require.ErrorContains(t, err, "does not contain authorized replace string", "ensure replace string") } + +// TestWorkspaceTableConvert verifies all workspace fields are converted +// when reducing a `Workspace` to a `WorkspaceTable`. +func TestWorkspaceTableConvert(t *testing.T) { + t.Parallel() + + var workspace Workspace + err := testutil.PopulateStruct(&workspace, nil) + require.NoError(t, err) + + workspace.WorkspaceTable() + require.JSONEq(t) + + fmt.Println(workspace) + +} diff --git a/testutil/reflect.go b/testutil/reflect.go new file mode 100644 index 0000000000000..b1e9b37899fda --- /dev/null +++ b/testutil/reflect.go @@ -0,0 +1,139 @@ +package testutil + +import ( + "fmt" + "reflect" + "time" +) + +type Random struct { + String func() string + Bool func() bool + Int func() int64 + Uint func() uint64 + Float func() float64 + Complex func() complex128 +} + +func NewRandom() *Random { + // Guaranteed to be random... + return &Random{ + String: func() string { return "foo" }, + Bool: func() bool { return true }, + Int: func() int64 { return 500 }, + Uint: func() uint64 { return 126 }, + Float: func() float64 { return 3.14 }, + Complex: func() complex128 { return 6.24 }, + } +} + +// PopulateStruct does a best effort to populate a struct with random values. +func PopulateStruct(s interface{}, r *Random) error { + if r == nil { + r = NewRandom() + } + + v := reflect.ValueOf(s) + if v.Kind() != reflect.Ptr || v.IsNil() { + return fmt.Errorf("s must be a non-nil pointer") + } + + v = v.Elem() + if v.Kind() != reflect.Struct { + return fmt.Errorf("s must be a pointer to a struct") + } + + t := v.Type() + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + fieldName := field.Name + + fieldValue := v.Field(i) + if !fieldValue.CanSet() { + continue // Skip if field is unexported + } + + nv, err := populateValue(fieldValue, r) + if err != nil { + return fmt.Errorf("%s : %w", fieldName, err) + } + v.Field(i).Set(nv) + } + + return nil +} + +func populateValue(v reflect.Value, r *Random) (reflect.Value, error) { + var err error + + // Handle some special cases + switch v.Type() { + case reflect.TypeOf(time.Time{}): + v.Set(reflect.ValueOf(time.Date(2020, 5, 2, 5, 19, 21, 30, time.UTC))) + return v, nil + } + + switch v.Kind() { + case reflect.Struct: + if err := PopulateStruct(v.Addr().Interface(), r); err != nil { + return v, err + } + case reflect.String: + v.SetString(r.String()) + case reflect.Bool: + v.SetBool(true) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + v.SetInt(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + v.SetUint(r.Uint()) + case reflect.Float32, reflect.Float64: + v.SetFloat(r.Float()) + case reflect.Complex64, reflect.Complex128: + v.SetComplex(r.Complex()) + case reflect.Array: + for i := 0; i < v.Len(); i++ { + nv, err := populateValue(v.Index(i), r) + if err != nil { + return v, fmt.Errorf("array index %d : %w", i, err) + } + v.Index(i).Set(nv) + } + case reflect.Map: + m := reflect.MakeMap(v.Type()) + + // Set a value in the map + k := reflect.New(v.Type().Key()) + kv := reflect.New(v.Type().Elem()) + k, err = populateValue(k, r) + if err != nil { + return v, fmt.Errorf("map key : %w", err) + } + kv, err = populateValue(kv, r) + if err != nil { + return v, fmt.Errorf("map value : %w", err) + } + + m.SetMapIndex(k, kv) + return m, nil + case reflect.Pointer: + return populateValue(v.Elem(), r) + case reflect.Slice: + s := reflect.MakeSlice(v.Type(), 2, 2) + sv, err := populateValue(reflect.New(v.Type().Elem()), r) + if err != nil { + return v, fmt.Errorf("slice value : %w", err) + } + + s.Index(0).Set(sv) + s.Index(1).Set(sv) + //reflect.AppendSlice(s, sv) + + return s, nil + case reflect.Uintptr, reflect.UnsafePointer, reflect.Chan, reflect.Func, reflect.Interface: + // Unsupported + return v, fmt.Errorf("%s is not supported", v.Kind()) + default: + return v, fmt.Errorf("unsupported kind %s", v.Kind()) + } + return v, nil +} From 90f2474649f99492c32ef306729066f463a2bba8 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 16 Oct 2024 17:29:47 -0500 Subject: [PATCH 06/23] add guard rail --- coderd/database/modelqueries_internal_test.go | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/coderd/database/modelqueries_internal_test.go b/coderd/database/modelqueries_internal_test.go index 2d15b91d297b1..d679156ef8442 100644 --- a/coderd/database/modelqueries_internal_test.go +++ b/coderd/database/modelqueries_internal_test.go @@ -1,7 +1,6 @@ package database import ( - "fmt" "testing" "github.com/stretchr/testify/require" @@ -19,16 +18,35 @@ func TestIsAuthorizedQuery(t *testing.T) { // TestWorkspaceTableConvert verifies all workspace fields are converted // when reducing a `Workspace` to a `WorkspaceTable`. +// This test is a guard rail to prevent developer oversight mistakes. func TestWorkspaceTableConvert(t *testing.T) { t.Parallel() + staticRandoms := &testutil.Random{ + String: func() string { return "foo" }, + Bool: func() bool { return true }, + Int: func() int64 { return 500 }, + Uint: func() uint64 { return 126 }, + Float: func() float64 { return 3.14 }, + Complex: func() complex128 { return 6.24 }, + } + + // This feels a bit janky, but it works. + // If you use 'PopulateStruct' to create 2 workspaces, using the same + // "random" values for each type. Then they should be identical. + // + // So if 'workspace.WorkspaceTable()' was missing any fields in its + // conversion, the comparison would fail. + var workspace Workspace - err := testutil.PopulateStruct(&workspace, nil) + err := testutil.PopulateStruct(&workspace, staticRandoms) require.NoError(t, err) - workspace.WorkspaceTable() - require.JSONEq(t) - - fmt.Println(workspace) + var subset WorkspaceTable + err = testutil.PopulateStruct(&subset, staticRandoms) + require.NoError(t, err) + require.Equal(t, workspace.WorkspaceTable(), subset, + "'workspace.WorkspaceTable()' is not missing at least 1 field when converting to 'WorkspaceTable'. "+ + "To resolve this, go to the 'func (w Workspace) WorkspaceTable()' and ensure all fields are converted.") } From 50fb16092167b8807ad109402b3fcfe6839e7c95 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 16 Oct 2024 17:52:23 -0500 Subject: [PATCH 07/23] more test fixes --- coderd/coderd_test.go | 2 +- coderd/database/dbfake/dbfake.go | 6 +-- coderd/database/dbmem/dbmem.go | 1 + coderd/database/dump.sql | 22 ++++---- .../000266_workspace_with_names.up.sql | 26 +++++----- coderd/metricscache/metricscache_test.go | 6 +-- coderd/users_test.go | 4 +- coderd/workspaceagentportshare_test.go | 6 +-- coderd/workspaceagents_test.go | 50 +++++++++--------- coderd/workspaceagentsrpc_test.go | 4 +- coderd/workspacebuilds_test.go | 2 +- coderd/workspaces_test.go | 52 +++++++++---------- enterprise/audit/diff_internal_test.go | 6 +-- enterprise/coderd/schedule/template.go | 2 +- enterprise/coderd/schedule/template_test.go | 14 ++--- 15 files changed, 102 insertions(+), 101 deletions(-) diff --git a/coderd/coderd_test.go b/coderd/coderd_test.go index f19c8d4c533dd..9e1d9154a07bc 100644 --- a/coderd/coderd_test.go +++ b/coderd/coderd_test.go @@ -355,7 +355,7 @@ func TestCSRFExempt(t *testing.T) { // Create a workspace. const agentSlug = "james" const appSlug = "web" - wrk := dbfake.WorkspaceBuild(t, api.Database, database.Workspace{ + wrk := dbfake.WorkspaceBuild(t, api.Database, database.WorkspaceTable{ OwnerID: owner.ID, OrganizationID: first.OrganizationID, }). diff --git a/coderd/database/dbfake/dbfake.go b/coderd/database/dbfake/dbfake.go index 4f9d6ddc5b28c..616dd2afac619 100644 --- a/coderd/database/dbfake/dbfake.go +++ b/coderd/database/dbfake/dbfake.go @@ -32,7 +32,7 @@ var ownerCtx = dbauthz.As(context.Background(), rbac.Subject{ }) type WorkspaceResponse struct { - Workspace database.Workspace + Workspace database.WorkspaceTable Build database.WorkspaceBuild AgentToken string TemplateVersionResponse @@ -44,7 +44,7 @@ type WorkspaceBuildBuilder struct { t testing.TB db database.Store ps pubsub.Pubsub - ws database.Workspace + ws database.WorkspaceTable seed database.WorkspaceBuild resources []*sdkproto.Resource params []database.WorkspaceBuildParameter @@ -60,7 +60,7 @@ type workspaceBuildDisposition struct { // Pass a database.Workspace{} with a nil ID to also generate a new workspace. // Omitting the template ID on a workspace will also generate a new template // with a template version. -func WorkspaceBuild(t testing.TB, db database.Store, ws database.Workspace) WorkspaceBuildBuilder { +func WorkspaceBuild(t testing.TB, db database.Store, ws database.WorkspaceTable) WorkspaceBuildBuilder { return WorkspaceBuildBuilder{t: t, db: db, ws: ws} } diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index 2e2b712055b1d..24498d88c9dbc 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -549,6 +549,7 @@ func (q *FakeQuerier) extendWorkspace(w database.WorkspaceTable) database.Worksp org, _ := slice.Find(q.organizations, func(o database.Organization) bool { return o.ID == w.OrganizationID }) + extended.OrganizationName = org.Name extended.OrganizationDescription = org.Description extended.OrganizationDisplayName = org.DisplayName extended.OrganizationIcon = org.Icon diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index 29e2c2d27ef18..c4e909a6ce0ed 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -1719,18 +1719,18 @@ CREATE VIEW workspaces_expanded AS workspaces.favorite, COALESCE(visible_users.avatar_url, ''::text) AS owner_avatar_url, COALESCE(visible_users.username, ''::text) AS owner_username, - COALESCE(organizations.name, ''::text) AS organization_name, - COALESCE(organizations.display_name, ''::text) AS organization_display_name, - COALESCE(organizations.icon, ''::text) AS organization_icon, - COALESCE(organizations.description, ''::text) AS organization_description, - COALESCE(templates.name, ''::character varying) AS template_name, - COALESCE(templates.display_name, ''::character varying) AS template_display_name, - COALESCE(templates.icon, ''::character varying) AS template_icon, - COALESCE(templates.description, ''::character varying) AS template_description + organizations.name AS organization_name, + organizations.display_name AS organization_display_name, + organizations.icon AS organization_icon, + organizations.description AS organization_description, + templates.name AS template_name, + templates.display_name AS template_display_name, + templates.icon AS template_icon, + templates.description AS template_description FROM (((workspaces - LEFT JOIN visible_users ON ((workspaces.owner_id = visible_users.id))) - LEFT JOIN organizations ON ((workspaces.organization_id = organizations.id))) - LEFT JOIN templates ON ((workspaces.template_id = templates.id))); + JOIN visible_users ON ((workspaces.owner_id = visible_users.id))) + JOIN organizations ON ((workspaces.organization_id = organizations.id))) + JOIN templates ON ((workspaces.template_id = templates.id))); COMMENT ON VIEW workspaces_expanded IS 'Joins in the display name information such as username, avatar, and organization name.'; diff --git a/coderd/database/migrations/000266_workspace_with_names.up.sql b/coderd/database/migrations/000266_workspace_with_names.up.sql index 392b003ddba8d..8264b17d8bbc1 100644 --- a/coderd/database/migrations/000266_workspace_with_names.up.sql +++ b/coderd/database/migrations/000266_workspace_with_names.up.sql @@ -4,28 +4,28 @@ AS SELECT workspaces.*, -- Owner - coalesce(visible_users.avatar_url, '') AS owner_avatar_url, - coalesce(visible_users.username, '') AS owner_username, + visible_users.avatar_url AS owner_avatar_url, + visible_users.username AS owner_username, -- Organization - coalesce(organizations.name, '') AS organization_name, - coalesce(organizations.display_name, '') AS organization_display_name, - coalesce(organizations.icon, '') AS organization_icon, - coalesce(organizations.description, '') AS organization_description, + organizations.name AS organization_name, + organizations.display_name AS organization_display_name, + organizations.icon AS organization_icon, + organizations.description AS organization_description, -- Template - coalesce(templates.name, '') AS template_name, - coalesce(templates.display_name, '') AS template_display_name, - coalesce(templates.icon, '') AS template_icon, - coalesce(templates.description, '') AS template_description + templates.name AS template_name, + templates.display_name AS template_display_name, + templates.icon AS template_icon, + templates.description AS template_description FROM workspaces - LEFT JOIN + INNER JOIN visible_users ON workspaces.owner_id = visible_users.id - LEFT JOIN + INNER JOIN organizations ON workspaces.organization_id = organizations.id - LEFT JOIN + INNER JOIN templates ON workspaces.template_id = templates.id ; diff --git a/coderd/metricscache/metricscache_test.go b/coderd/metricscache/metricscache_test.go index 891a66738c803..f854d21e777b0 100644 --- a/coderd/metricscache/metricscache_test.go +++ b/coderd/metricscache/metricscache_test.go @@ -49,7 +49,7 @@ func TestCache_TemplateWorkspaceOwners(t *testing.T) { "TemplateWorkspaceOwners never populated 0 owners", ) - dbgen.Workspace(t, db, database.Workspace{ + dbgen.Workspace(t, db, database.WorkspaceTable{ TemplateID: template.ID, OwnerID: user1.ID, }) @@ -61,7 +61,7 @@ func TestCache_TemplateWorkspaceOwners(t *testing.T) { "TemplateWorkspaceOwners never populated 1 owner", ) - workspace2 := dbgen.Workspace(t, db, database.Workspace{ + workspace2 := dbgen.Workspace(t, db, database.WorkspaceTable{ TemplateID: template.ID, OwnerID: user2.ID, }) @@ -74,7 +74,7 @@ func TestCache_TemplateWorkspaceOwners(t *testing.T) { ) // 3rd workspace should not be counted since we have the same owner as workspace2. - dbgen.Workspace(t, db, database.Workspace{ + dbgen.Workspace(t, db, database.WorkspaceTable{ TemplateID: template.ID, OwnerID: user1.ID, }) diff --git a/coderd/users_test.go b/coderd/users_test.go index ff7c63e63bebc..bd66bdb1d9a09 100644 --- a/coderd/users_test.go +++ b/coderd/users_test.go @@ -1936,7 +1936,7 @@ func TestUserAutofillParameters(t *testing.T) { }, ).Do() - dbfake.WorkspaceBuild(t, db, database.Workspace{ + dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OwnerID: u2.ID, TemplateID: version.Template.ID, OrganizationID: u1.OrganizationID, @@ -1969,7 +1969,7 @@ func TestUserAutofillParameters(t *testing.T) { require.Equal(t, "foo", params[0].Value) // Verify that latest parameter value is returned. - dbfake.WorkspaceBuild(t, db, database.Workspace{ + dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: u1.OrganizationID, OwnerID: u2.ID, TemplateID: version.Template.ID, diff --git a/coderd/workspaceagentportshare_test.go b/coderd/workspaceagentportshare_test.go index f767aed933562..201ba68f3d6c5 100644 --- a/coderd/workspaceagentportshare_test.go +++ b/coderd/workspaceagentportshare_test.go @@ -24,7 +24,7 @@ func TestPostWorkspaceAgentPortShare(t *testing.T) { client, user := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID) tmpDir := t.TempDir() - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: owner.OrganizationID, OwnerID: user.ID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { @@ -141,7 +141,7 @@ func TestGetWorkspaceAgentPortShares(t *testing.T) { client, user := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID) tmpDir := t.TempDir() - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: owner.OrganizationID, OwnerID: user.ID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { @@ -177,7 +177,7 @@ func TestDeleteWorkspaceAgentPortShare(t *testing.T) { client, user := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID) tmpDir := t.TempDir() - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: owner.OrganizationID, OwnerID: user.ID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { diff --git a/coderd/workspaceagents_test.go b/coderd/workspaceagents_test.go index 906333456ae70..8c0801a914d61 100644 --- a/coderd/workspaceagents_test.go +++ b/coderd/workspaceagents_test.go @@ -57,7 +57,7 @@ func TestWorkspaceAgent(t *testing.T) { tmpDir := t.TempDir() anotherClient, anotherUser := coderdtest.CreateAnotherUser(t, client, user.OrganizationID) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: anotherUser.ID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { @@ -79,7 +79,7 @@ func TestWorkspaceAgent(t *testing.T) { client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) tmpDir := t.TempDir() - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { @@ -107,7 +107,7 @@ func TestWorkspaceAgent(t *testing.T) { wantTroubleshootingURL := "https://example.com/troubleshoot" - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { @@ -148,7 +148,7 @@ func TestWorkspaceAgent(t *testing.T) { PortForwardingHelper: true, SshHelper: true, } - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { @@ -181,7 +181,7 @@ func TestWorkspaceAgent(t *testing.T) { apps.WebTerminal = false // Creating another workspace is easier - r = dbfake.WorkspaceBuild(t, db, database.Workspace{ + r = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { @@ -205,7 +205,7 @@ func TestWorkspaceAgentLogs(t *testing.T) { ctx := testutil.Context(t, testutil.WaitMedium) client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent().Do() @@ -247,7 +247,7 @@ func TestWorkspaceAgentLogs(t *testing.T) { ctx := testutil.Context(t, testutil.WaitMedium) client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent().Do() @@ -289,7 +289,7 @@ func TestWorkspaceAgentLogs(t *testing.T) { ctx := testutil.Context(t, testutil.WaitMedium) client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent().Do() @@ -332,7 +332,7 @@ func TestWorkspaceAgentConnectRPC(t *testing.T) { client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent().Do() @@ -420,7 +420,7 @@ func TestWorkspaceAgentConnectRPC(t *testing.T) { client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) // Given: a workspace exists - seed := database.Workspace{OrganizationID: user.OrganizationID, OwnerID: user.UserID} + seed := database.WorkspaceTable{OrganizationID: user.OrganizationID, OwnerID: user.UserID} wsb := dbfake.WorkspaceBuild(t, db, seed).WithAgent().Do() // When: the workspace is marked as soft-deleted // nolint:gocritic // this is a test @@ -446,7 +446,7 @@ func TestWorkspaceAgentTailnet(t *testing.T) { client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent().Do() @@ -486,7 +486,7 @@ func TestWorkspaceAgentClientCoordinate_BadVersion(t *testing.T) { client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent().Do() @@ -571,7 +571,7 @@ func TestWorkspaceAgentClientCoordinate_ResumeToken(t *testing.T) { // Create a workspace with an agent. No need to connect it since clients can // still connect to the coordinator while the agent isn't connected. - r := dbfake.WorkspaceBuild(t, api.Database, database.Workspace{ + r := dbfake.WorkspaceBuild(t, api.Database, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent().Do() @@ -679,7 +679,7 @@ func TestWorkspaceAgentTailnetDirectDisabled(t *testing.T) { DeploymentValues: dv, }) user := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent().Do() @@ -750,7 +750,7 @@ func TestWorkspaceAgentListeningPorts(t *testing.T) { require.NoError(t, err) user := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { @@ -1006,7 +1006,7 @@ func TestWorkspaceAgentAppHealth(t *testing.T) { }, }, } - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { @@ -1088,7 +1088,7 @@ func TestWorkspaceAgentPostLogSource(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) ctx := testutil.Context(t, testutil.WaitShort) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent().Do() @@ -1130,7 +1130,7 @@ func TestWorkspaceAgent_LifecycleState(t *testing.T) { client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent().Do() @@ -1203,7 +1203,7 @@ func TestWorkspaceAgent_Metadata(t *testing.T) { client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { @@ -1368,7 +1368,7 @@ func TestWorkspaceAgent_Metadata_DisplayOrder(t *testing.T) { client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { @@ -1475,7 +1475,7 @@ func TestWorkspaceAgent_Metadata_CatchMemoryLeak(t *testing.T) { Logger: &logger, }) user := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { @@ -1607,7 +1607,7 @@ func TestWorkspaceAgent_Startup(t *testing.T) { client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent().Do() @@ -1653,7 +1653,7 @@ func TestWorkspaceAgent_Startup(t *testing.T) { client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent().Do() @@ -1698,7 +1698,7 @@ func TestWorkspaceAgent_UpdatedDERP(t *testing.T) { api.DERPMapper.Store(&derpMapFn) // Start workspace a workspace agent. - r := dbfake.WorkspaceBuild(t, api.Database, database.Workspace{ + r := dbfake.WorkspaceBuild(t, api.Database, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent().Do() @@ -1815,7 +1815,7 @@ func TestWorkspaceAgentExternalAuthListen(t *testing.T) { tmpDir := t.TempDir() client, user := coderdtest.CreateAnotherUser(t, ownerClient, first.OrganizationID) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: first.OrganizationID, OwnerID: user.ID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { diff --git a/coderd/workspaceagentsrpc_test.go b/coderd/workspaceagentsrpc_test.go index ca8f334d4e766..817aa11c4c292 100644 --- a/coderd/workspaceagentsrpc_test.go +++ b/coderd/workspaceagentsrpc_test.go @@ -22,7 +22,7 @@ func TestWorkspaceAgentReportStats(t *testing.T) { client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent().Do() @@ -72,7 +72,7 @@ func TestAgentAPI_LargeManifest(t *testing.T) { for i := range longScript { longScript[i] = 'q' } - r := dbfake.WorkspaceBuild(t, store, database.Workspace{ + r := dbfake.WorkspaceBuild(t, store, database.WorkspaceTable{ OrganizationID: adminUser.OrganizationID, OwnerID: adminUser.UserID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { diff --git a/coderd/workspacebuilds_test.go b/coderd/workspacebuilds_test.go index ec20556a7b2ed..e8eeca0f49d66 100644 --- a/coderd/workspacebuilds_test.go +++ b/coderd/workspacebuilds_test.go @@ -1217,7 +1217,7 @@ func TestWorkspaceBuildTimings(t *testing.T) { // Tests will run in parallel. To avoid conflicts and race conditions on the // build number, each test will have its own workspace and build. makeBuild := func() database.WorkspaceBuild { - ws := dbgen.Workspace(t, db, database.Workspace{ + ws := dbgen.Workspace(t, db, database.WorkspaceTable{ OwnerID: owner.UserID, OrganizationID: owner.OrganizationID, TemplateID: template.ID, diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index dc83289340059..c24afc67de8ba 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -392,7 +392,7 @@ func TestResolveAutostart(t *testing.T) { defer cancel() client, member := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID) - resp := dbfake.WorkspaceBuild(t, db, database.Workspace{ + resp := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OwnerID: member.ID, OrganizationID: owner.OrganizationID, AutomaticUpdates: database.AutomaticUpdatesAlways, @@ -456,22 +456,22 @@ func TestWorkspacesSortOrder(t *testing.T) { }) // c-workspace should be running - wsbC := dbfake.WorkspaceBuild(t, db, database.Workspace{Name: "c-workspace", OwnerID: firstUser.UserID, OrganizationID: firstUser.OrganizationID}).Do() + wsbC := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{Name: "c-workspace", OwnerID: firstUser.UserID, OrganizationID: firstUser.OrganizationID}).Do() // b-workspace should be stopped - wsbB := dbfake.WorkspaceBuild(t, db, database.Workspace{Name: "b-workspace", OwnerID: firstUser.UserID, OrganizationID: firstUser.OrganizationID}).Seed(database.WorkspaceBuild{Transition: database.WorkspaceTransitionStop}).Do() + wsbB := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{Name: "b-workspace", OwnerID: firstUser.UserID, OrganizationID: firstUser.OrganizationID}).Seed(database.WorkspaceBuild{Transition: database.WorkspaceTransitionStop}).Do() // a-workspace should be running - wsbA := dbfake.WorkspaceBuild(t, db, database.Workspace{Name: "a-workspace", OwnerID: firstUser.UserID, OrganizationID: firstUser.OrganizationID}).Do() + wsbA := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{Name: "a-workspace", OwnerID: firstUser.UserID, OrganizationID: firstUser.OrganizationID}).Do() // d-workspace should be stopped - wsbD := dbfake.WorkspaceBuild(t, db, database.Workspace{Name: "d-workspace", OwnerID: secondUser.ID, OrganizationID: firstUser.OrganizationID}).Seed(database.WorkspaceBuild{Transition: database.WorkspaceTransitionStop}).Do() + wsbD := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{Name: "d-workspace", OwnerID: secondUser.ID, OrganizationID: firstUser.OrganizationID}).Seed(database.WorkspaceBuild{Transition: database.WorkspaceTransitionStop}).Do() // e-workspace should also be stopped - wsbE := dbfake.WorkspaceBuild(t, db, database.Workspace{Name: "e-workspace", OwnerID: secondUser.ID, OrganizationID: firstUser.OrganizationID}).Seed(database.WorkspaceBuild{Transition: database.WorkspaceTransitionStop}).Do() + wsbE := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{Name: "e-workspace", OwnerID: secondUser.ID, OrganizationID: firstUser.OrganizationID}).Seed(database.WorkspaceBuild{Transition: database.WorkspaceTransitionStop}).Do() // f-workspace is also stopped, but is marked as favorite - wsbF := dbfake.WorkspaceBuild(t, db, database.Workspace{Name: "f-workspace", OwnerID: firstUser.UserID, OrganizationID: firstUser.OrganizationID}).Seed(database.WorkspaceBuild{Transition: database.WorkspaceTransitionStop}).Do() + wsbF := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{Name: "f-workspace", OwnerID: firstUser.UserID, OrganizationID: firstUser.OrganizationID}).Seed(database.WorkspaceBuild{Transition: database.WorkspaceTransitionStop}).Do() ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() @@ -905,7 +905,7 @@ func TestWorkspaceFilterAllStatus(t *testing.T) { CreatedBy: owner.UserID, }) - makeWorkspace := func(workspace database.Workspace, job database.ProvisionerJob, transition database.WorkspaceTransition) (database.Workspace, database.WorkspaceBuild, database.ProvisionerJob) { + makeWorkspace := func(workspace database.WorkspaceTable, job database.ProvisionerJob, transition database.WorkspaceTransition) (database.WorkspaceTable, database.WorkspaceBuild, database.ProvisionerJob) { db := db workspace.OwnerID = owner.UserID @@ -940,21 +940,21 @@ func TestWorkspaceFilterAllStatus(t *testing.T) { } // pending - makeWorkspace(database.Workspace{ + makeWorkspace(database.WorkspaceTable{ Name: string(database.WorkspaceStatusPending), }, database.ProvisionerJob{ StartedAt: sql.NullTime{Valid: false}, }, database.WorkspaceTransitionStart) // starting - makeWorkspace(database.Workspace{ + makeWorkspace(database.WorkspaceTable{ Name: string(database.WorkspaceStatusStarting), }, database.ProvisionerJob{ StartedAt: sql.NullTime{Time: time.Now().Add(time.Second * -2), Valid: true}, }, database.WorkspaceTransitionStart) // running - makeWorkspace(database.Workspace{ + makeWorkspace(database.WorkspaceTable{ Name: string(database.WorkspaceStatusRunning), }, database.ProvisionerJob{ CompletedAt: sql.NullTime{Time: time.Now(), Valid: true}, @@ -962,14 +962,14 @@ func TestWorkspaceFilterAllStatus(t *testing.T) { }, database.WorkspaceTransitionStart) // stopping - makeWorkspace(database.Workspace{ + makeWorkspace(database.WorkspaceTable{ Name: string(database.WorkspaceStatusStopping), }, database.ProvisionerJob{ StartedAt: sql.NullTime{Time: time.Now().Add(time.Second * -2), Valid: true}, }, database.WorkspaceTransitionStop) // stopped - makeWorkspace(database.Workspace{ + makeWorkspace(database.WorkspaceTable{ Name: string(database.WorkspaceStatusStopped), }, database.ProvisionerJob{ StartedAt: sql.NullTime{Time: time.Now().Add(time.Second * -2), Valid: true}, @@ -977,7 +977,7 @@ func TestWorkspaceFilterAllStatus(t *testing.T) { }, database.WorkspaceTransitionStop) // failed -- delete - makeWorkspace(database.Workspace{ + makeWorkspace(database.WorkspaceTable{ Name: string(database.WorkspaceStatusFailed) + "-deleted", }, database.ProvisionerJob{ StartedAt: sql.NullTime{Time: time.Now().Add(time.Second * -2), Valid: true}, @@ -986,7 +986,7 @@ func TestWorkspaceFilterAllStatus(t *testing.T) { }, database.WorkspaceTransitionDelete) // failed -- stop - makeWorkspace(database.Workspace{ + makeWorkspace(database.WorkspaceTable{ Name: string(database.WorkspaceStatusFailed) + "-stopped", }, database.ProvisionerJob{ StartedAt: sql.NullTime{Time: time.Now().Add(time.Second * -2), Valid: true}, @@ -995,7 +995,7 @@ func TestWorkspaceFilterAllStatus(t *testing.T) { }, database.WorkspaceTransitionStop) // canceling - makeWorkspace(database.Workspace{ + makeWorkspace(database.WorkspaceTable{ Name: string(database.WorkspaceStatusCanceling), }, database.ProvisionerJob{ StartedAt: sql.NullTime{Time: time.Now().Add(time.Second * -2), Valid: true}, @@ -1003,7 +1003,7 @@ func TestWorkspaceFilterAllStatus(t *testing.T) { }, database.WorkspaceTransitionStart) // canceled - makeWorkspace(database.Workspace{ + makeWorkspace(database.WorkspaceTable{ Name: string(database.WorkspaceStatusCanceled), }, database.ProvisionerJob{ StartedAt: sql.NullTime{Time: time.Now().Add(time.Second * -2), Valid: true}, @@ -1012,14 +1012,14 @@ func TestWorkspaceFilterAllStatus(t *testing.T) { }, database.WorkspaceTransitionStart) // deleting - makeWorkspace(database.Workspace{ + makeWorkspace(database.WorkspaceTable{ Name: string(database.WorkspaceStatusDeleting), }, database.ProvisionerJob{ StartedAt: sql.NullTime{Time: time.Now().Add(time.Second * -2), Valid: true}, }, database.WorkspaceTransitionDelete) // deleted - makeWorkspace(database.Workspace{ + makeWorkspace(database.WorkspaceTable{ Name: string(database.WorkspaceStatusDeleted), }, database.ProvisionerJob{ StartedAt: sql.NullTime{Time: time.Now().Add(time.Second * -2), Valid: true}, @@ -1567,14 +1567,14 @@ func TestWorkspaceFilterManual(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() - dormantWorkspace := dbfake.WorkspaceBuild(t, db, database.Workspace{ + dormantWorkspace := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ TemplateID: template.ID, OwnerID: user.UserID, OrganizationID: user.OrganizationID, }).Do().Workspace // Create another workspace to validate that we do not return active workspaces. - _ = dbfake.WorkspaceBuild(t, db, database.Workspace{ + _ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ TemplateID: template.ID, OwnerID: user.UserID, OrganizationID: user.OrganizationID, @@ -3246,8 +3246,8 @@ func TestWorkspaceFavoriteUnfavorite(t *testing.T) { owner = coderdtest.CreateFirstUser(t, client) memberClient, member = coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) // This will be our 'favorite' workspace - wsb1 = dbfake.WorkspaceBuild(t, db, database.Workspace{OwnerID: member.ID, OrganizationID: owner.OrganizationID}).Do() - wsb2 = dbfake.WorkspaceBuild(t, db, database.Workspace{OwnerID: owner.UserID, OrganizationID: owner.OrganizationID}).Do() + wsb1 = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{OwnerID: member.ID, OrganizationID: owner.OrganizationID}).Do() + wsb2 = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{OwnerID: owner.UserID, OrganizationID: owner.OrganizationID}).Do() ) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -3324,7 +3324,7 @@ func TestWorkspaceUsageTracking(t *testing.T) { client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) tmpDir := t.TempDir() - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { @@ -3371,7 +3371,7 @@ func TestWorkspaceUsageTracking(t *testing.T) { ActivityBumpMillis: 8 * time.Hour.Milliseconds(), }) require.NoError(t, err) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, TemplateID: template.ID, @@ -3598,7 +3598,7 @@ func TestWorkspaceTimings(t *testing.T) { ActiveVersionID: version.ID, CreatedBy: owner.UserID, }) - ws := dbgen.Workspace(t, db, database.Workspace{ + ws := dbgen.Workspace(t, db, database.WorkspaceTable{ OwnerID: owner.UserID, OrganizationID: owner.OrganizationID, TemplateID: template.ID, diff --git a/enterprise/audit/diff_internal_test.go b/enterprise/audit/diff_internal_test.go index f98d16138cf1f..08a7153c72930 100644 --- a/enterprise/audit/diff_internal_test.go +++ b/enterprise/audit/diff_internal_test.go @@ -370,8 +370,8 @@ func Test_diff(t *testing.T) { runDiffTests(t, []diffTest{ { name: "Create", - left: audit.Empty[database.Workspace](), - right: database.Workspace{ + left: audit.Empty[database.WorkspaceTable](), + right: database.WorkspaceTable{ ID: uuid.UUID{1}, CreatedAt: time.Now(), UpdatedAt: time.Now(), @@ -392,7 +392,7 @@ func Test_diff(t *testing.T) { }, { name: "NullSchedules", - left: audit.Empty[database.Workspace](), + left: audit.Empty[database.WorkspaceTable](), right: database.Workspace{ ID: uuid.UUID{1}, CreatedAt: time.Now(), diff --git a/enterprise/coderd/schedule/template.go b/enterprise/coderd/schedule/template.go index 6b148e8ef4708..7ac428f102e4d 100644 --- a/enterprise/coderd/schedule/template.go +++ b/enterprise/coderd/schedule/template.go @@ -136,7 +136,7 @@ func (s *EnterpriseTemplateScheduleStore) Set(ctx context.Context, db database.S var ( template database.Template - markedForDeletion []database.Workspace + markedForDeletion []database.WorkspaceTable ) err = db.InTx(func(tx database.Store) error { ctx, span := tracing.StartSpanWithName(ctx, "(*schedule.EnterpriseTemplateScheduleStore).Set()-InTx()") diff --git a/enterprise/coderd/schedule/template_test.go b/enterprise/coderd/schedule/template_test.go index bce5ffbec930e..c85c2c6ea1b0e 100644 --- a/enterprise/coderd/schedule/template_test.go +++ b/enterprise/coderd/schedule/template_test.go @@ -211,7 +211,7 @@ func TestTemplateUpdateBuildDeadlines(t *testing.T) { ActiveVersionID: templateVersion.ID, CreatedBy: user.ID, }) - ws = dbgen.Workspace(t, db, database.Workspace{ + ws = dbgen.Workspace(t, db, database.WorkspaceTable{ OrganizationID: organizationID, OwnerID: user.ID, TemplateID: template.ID, @@ -357,7 +357,7 @@ func TestTemplateUpdateBuildDeadlinesSkip(t *testing.T) { ) // Create a workspace that will be shared by two builds. - ws := dbgen.Workspace(t, db, database.Workspace{ + ws := dbgen.Workspace(t, db, database.WorkspaceTable{ OwnerID: user.ID, TemplateID: template.ID, OrganizationID: templateJob.OrganizationID, @@ -474,7 +474,7 @@ func TestTemplateUpdateBuildDeadlinesSkip(t *testing.T) { for i, b := range builds { wsID := b.workspaceID if wsID == uuid.Nil { - ws := dbgen.Workspace(t, db, database.Workspace{ + ws := dbgen.Workspace(t, db, database.WorkspaceTable{ OwnerID: user.ID, TemplateID: b.templateID, OrganizationID: templateJob.OrganizationID, @@ -642,21 +642,21 @@ func TestNotifications(t *testing.T) { ) // Add two dormant workspaces and one active workspace. - dormantWorkspaces := []database.Workspace{ - dbgen.Workspace(t, db, database.Workspace{ + dormantWorkspaces := []database.WorkspaceTable{ + dbgen.Workspace(t, db, database.WorkspaceTable{ OwnerID: user.ID, TemplateID: template.ID, OrganizationID: templateJob.OrganizationID, LastUsedAt: time.Now().Add(-time.Hour), }), - dbgen.Workspace(t, db, database.Workspace{ + dbgen.Workspace(t, db, database.WorkspaceTable{ OwnerID: user.ID, TemplateID: template.ID, OrganizationID: templateJob.OrganizationID, LastUsedAt: time.Now().Add(-time.Hour), }), } - dbgen.Workspace(t, db, database.Workspace{ + dbgen.Workspace(t, db, database.WorkspaceTable{ OwnerID: user.ID, TemplateID: template.ID, OrganizationID: templateJob.OrganizationID, From f18c801de29bb59028d49a8a9b30b07682ddea14 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 17 Oct 2024 16:34:07 -0500 Subject: [PATCH 08/23] fix dgen calls --- cli/configssh_test.go | 6 +- coderd/database/dbauthz/dbauthz_test.go | 134 +++++++++--------- coderd/database/dbgen/dbgen_test.go | 4 +- coderd/database/dbpurge/dbpurge_test.go | 10 +- coderd/database/dbrollup/dbrollup_test.go | 4 +- coderd/httpmw/workspaceagent_test.go | 2 +- coderd/httpmw/workspaceagentparam_test.go | 2 +- coderd/httpmw/workspacebuildparam_test.go | 2 +- coderd/httpmw/workspaceparam_test.go | 2 +- .../reports/generator_internal_test.go | 14 +- .../insights/metricscollector_test.go | 4 +- .../provisionerdserver_test.go | 10 +- coderd/schedule/autostop_test.go | 2 +- coderd/telemetry/telemetry_test.go | 2 +- coderd/unhanger/detector_test.go | 6 +- coderd/users.go | 9 -- coderd/workspacebuilds.go | 2 +- coderd/workspacestats/activitybump_test.go | 2 +- .../workspacestats/batcher_internal_test.go | 2 +- coderd/workspacestats/tracker_test.go | 2 +- enterprise/coderd/appearance_test.go | 2 +- enterprise/coderd/workspaces_test.go | 10 +- support/support_test.go | 2 +- 23 files changed, 113 insertions(+), 122 deletions(-) diff --git a/cli/configssh_test.go b/cli/configssh_test.go index feead1e279e96..5bedd18cb27dc 100644 --- a/cli/configssh_test.go +++ b/cli/configssh_test.go @@ -83,7 +83,7 @@ func TestConfigSSH(t *testing.T) { }) owner := coderdtest.CreateFirstUser(t, client) member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: owner.OrganizationID, OwnerID: memberUser.ID, }).WithAgent().Do() @@ -647,7 +647,7 @@ func TestConfigSSH_FileWriteAndOptionsFlow(t *testing.T) { client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) if tt.hasAgent { - _ = dbfake.WorkspaceBuild(t, db, database.Workspace{ + _ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent().Do() @@ -767,7 +767,7 @@ func TestConfigSSH_Hostnames(t *testing.T) { owner := coderdtest.CreateFirstUser(t, client) member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: owner.OrganizationID, OwnerID: memberUser.ID, }).Resource(resources...).Do() diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index f554d709ad4d0..68f6ff6fc67ac 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -90,7 +90,7 @@ func TestInTX(t *testing.T) { Scope: rbac.ScopeAll, } - w := dbgen.Workspace(t, db, database.Workspace{}) + w := dbgen.Workspace(t, db, database.WorkspaceTable{}) ctx := dbauthz.As(context.Background(), actor) err := q.InTx(func(tx database.Store) error { // The inner tx should use the parent's authz @@ -108,7 +108,7 @@ func TestNew(t *testing.T) { var ( db = dbmem.New() - exp = dbgen.Workspace(t, db, database.Workspace{}) + exp = dbgen.Workspace(t, db, database.WorkspaceTable{}) rec = &coderdtest.RecordingAuthorizer{ Wrapped: &coderdtest.FakeAuthorizer{}, } @@ -465,7 +465,7 @@ func (s *MethodTestSuite) TestProvisionerJob() { }).Asserts(v.RBACObject(tpl), policy.ActionUpdate) })) s.Run("Build/GetProvisionerJobByID", s.Subtest(func(db database.Store, check *expects) { - w := dbgen.Workspace(s.T(), db, database.Workspace{}) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ Type: database.ProvisionerJobTypeWorkspaceBuild, }) @@ -498,7 +498,7 @@ func (s *MethodTestSuite) TestProvisionerJob() { })) s.Run("Build/UpdateProvisionerJobWithCancelByID", s.Subtest(func(db database.Store, check *expects) { tpl := dbgen.Template(s.T(), db, database.Template{AllowUserCancelWorkspaceJobs: true}) - w := dbgen.Workspace(s.T(), db, database.Workspace{TemplateID: tpl.ID}) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{TemplateID: tpl.ID}) j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ Type: database.ProvisionerJobTypeWorkspaceBuild, }) @@ -507,7 +507,7 @@ func (s *MethodTestSuite) TestProvisionerJob() { })) s.Run("BuildFalseCancel/UpdateProvisionerJobWithCancelByID", s.Subtest(func(db database.Store, check *expects) { tpl := dbgen.Template(s.T(), db, database.Template{AllowUserCancelWorkspaceJobs: false}) - w := dbgen.Workspace(s.T(), db, database.Workspace{TemplateID: tpl.ID}) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{TemplateID: tpl.ID}) j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ Type: database.ProvisionerJobTypeWorkspaceBuild, }) @@ -557,7 +557,7 @@ func (s *MethodTestSuite) TestProvisionerJob() { check.Args([]uuid.UUID{a.ID, b.ID}).Asserts().Returns(slice.New(a, b)) })) s.Run("GetProvisionerLogsAfterID", s.Subtest(func(db database.Store, check *expects) { - w := dbgen.Workspace(s.T(), db, database.Workspace{}) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ Type: database.ProvisionerJobTypeWorkspaceBuild, }) @@ -1455,29 +1455,29 @@ func (s *MethodTestSuite) TestUser() { func (s *MethodTestSuite) TestWorkspace() { s.Run("GetWorkspaceByID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) check.Args(ws.ID).Asserts(ws, policy.ActionRead) })) s.Run("GetWorkspaces", s.Subtest(func(db database.Store, check *expects) { - _ = dbgen.Workspace(s.T(), db, database.Workspace{}) - _ = dbgen.Workspace(s.T(), db, database.Workspace{}) + _ = dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) + _ = dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) // No asserts here because SQLFilter. check.Args(database.GetWorkspacesParams{}).Asserts() })) s.Run("GetAuthorizedWorkspaces", s.Subtest(func(db database.Store, check *expects) { - _ = dbgen.Workspace(s.T(), db, database.Workspace{}) - _ = dbgen.Workspace(s.T(), db, database.Workspace{}) + _ = dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) + _ = dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) // No asserts here because SQLFilter. check.Args(database.GetWorkspacesParams{}, emptyPreparedAuthorized{}).Asserts() })) s.Run("GetLatestWorkspaceBuildByWorkspaceID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID}) check.Args(ws.ID).Asserts(ws, policy.ActionRead).Returns(b) })) s.Run("GetWorkspaceAgentByID", s.Subtest(func(db database.Store, check *expects) { tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{ + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ TemplateID: tpl.ID, }) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) @@ -1487,7 +1487,7 @@ func (s *MethodTestSuite) TestWorkspace() { })) s.Run("GetWorkspaceAgentLifecycleStateByID", s.Subtest(func(db database.Store, check *expects) { tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{ + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ TemplateID: tpl.ID, }) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) @@ -1497,7 +1497,7 @@ func (s *MethodTestSuite) TestWorkspace() { })) s.Run("GetWorkspaceAgentMetadata", s.Subtest(func(db database.Store, check *expects) { tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{ + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ TemplateID: tpl.ID, }) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) @@ -1515,7 +1515,7 @@ func (s *MethodTestSuite) TestWorkspace() { })) s.Run("GetWorkspaceAgentByInstanceID", s.Subtest(func(db database.Store, check *expects) { tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{ + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ TemplateID: tpl.ID, }) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) @@ -1525,7 +1525,7 @@ func (s *MethodTestSuite) TestWorkspace() { })) s.Run("UpdateWorkspaceAgentLifecycleStateByID", s.Subtest(func(db database.Store, check *expects) { tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{ + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ TemplateID: tpl.ID, }) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) @@ -1538,7 +1538,7 @@ func (s *MethodTestSuite) TestWorkspace() { })) s.Run("UpdateWorkspaceAgentMetadata", s.Subtest(func(db database.Store, check *expects) { tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{ + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ TemplateID: tpl.ID, }) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) @@ -1550,7 +1550,7 @@ func (s *MethodTestSuite) TestWorkspace() { })) s.Run("UpdateWorkspaceAgentLogOverflowByID", s.Subtest(func(db database.Store, check *expects) { tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{ + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ TemplateID: tpl.ID, }) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) @@ -1563,7 +1563,7 @@ func (s *MethodTestSuite) TestWorkspace() { })) s.Run("UpdateWorkspaceAgentStartupByID", s.Subtest(func(db database.Store, check *expects) { tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{ + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ TemplateID: tpl.ID, }) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) @@ -1578,7 +1578,7 @@ func (s *MethodTestSuite) TestWorkspace() { })) s.Run("GetWorkspaceAgentLogsAfter", s.Subtest(func(db database.Store, check *expects) { tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{ + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ TemplateID: tpl.ID, }) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) @@ -1590,7 +1590,7 @@ func (s *MethodTestSuite) TestWorkspace() { })) s.Run("GetWorkspaceAppByAgentIDAndSlug", s.Subtest(func(db database.Store, check *expects) { tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{ + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ TemplateID: tpl.ID, }) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) @@ -1605,7 +1605,7 @@ func (s *MethodTestSuite) TestWorkspace() { })) s.Run("GetWorkspaceAppsByAgentID", s.Subtest(func(db database.Store, check *expects) { tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{ + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ TemplateID: tpl.ID, }) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) @@ -1617,17 +1617,17 @@ func (s *MethodTestSuite) TestWorkspace() { check.Args(agt.ID).Asserts(ws, policy.ActionRead).Returns(slice.New(a, b)) })) s.Run("GetWorkspaceBuildByID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID}) check.Args(build.ID).Asserts(ws, policy.ActionRead).Returns(build) })) s.Run("GetWorkspaceBuildByJobID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID}) check.Args(build.JobID).Asserts(ws, policy.ActionRead).Returns(build) })) s.Run("GetWorkspaceBuildByWorkspaceIDAndBuildNumber", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, BuildNumber: 10}) check.Args(database.GetWorkspaceBuildByWorkspaceIDAndBuildNumberParams{ WorkspaceID: ws.ID, @@ -1635,13 +1635,13 @@ func (s *MethodTestSuite) TestWorkspace() { }).Asserts(ws, policy.ActionRead).Returns(build) })) s.Run("GetWorkspaceBuildParameters", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID}) check.Args(build.ID).Asserts(ws, policy.ActionRead). Returns([]database.WorkspaceBuildParameter{}) })) s.Run("GetWorkspaceBuildsByWorkspaceID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, BuildNumber: 1}) _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, BuildNumber: 2}) _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, BuildNumber: 3}) @@ -1649,20 +1649,20 @@ func (s *MethodTestSuite) TestWorkspace() { })) s.Run("GetWorkspaceByAgentID", s.Subtest(func(db database.Store, check *expects) { tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{ + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ TemplateID: tpl.ID, }) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) - check.Args(agt.ID).Asserts(ws, policy.ActionRead).Returns(database.GetWorkspaceByAgentIDRow{ + check.Args(agt.ID).Asserts(ws, policy.ActionRead).Returns(database.Workspace{ Workspace: ws, TemplateName: tpl.Name, }) })) s.Run("GetWorkspaceAgentsInLatestBuildByWorkspaceID", s.Subtest(func(db database.Store, check *expects) { tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{ + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ TemplateID: tpl.ID, }) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) @@ -1671,7 +1671,7 @@ func (s *MethodTestSuite) TestWorkspace() { check.Args(ws.ID).Asserts(ws, policy.ActionRead) })) s.Run("GetWorkspaceByOwnerIDAndName", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) check.Args(database.GetWorkspaceByOwnerIDAndNameParams{ OwnerID: ws.OwnerID, Deleted: ws.Deleted, @@ -1679,14 +1679,14 @@ func (s *MethodTestSuite) TestWorkspace() { }).Asserts(ws, policy.ActionRead).Returns(ws) })) s.Run("GetWorkspaceResourceByID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) _ = dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ID: build.JobID, Type: database.ProvisionerJobTypeWorkspaceBuild}) res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) check.Args(res.ID).Asserts(ws, policy.ActionRead).Returns(res) })) s.Run("Build/GetWorkspaceResourcesByJobID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) job := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ID: build.JobID, Type: database.ProvisionerJobTypeWorkspaceBuild}) check.Args(job.ID).Asserts(ws, policy.ActionRead).Returns([]database.WorkspaceResource{}) @@ -1709,7 +1709,7 @@ func (s *MethodTestSuite) TestWorkspace() { })) s.Run("Start/InsertWorkspaceBuild", s.Subtest(func(db database.Store, check *expects) { t := dbgen.Template(s.T(), db, database.Template{}) - w := dbgen.Workspace(s.T(), db, database.Workspace{ + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ TemplateID: t.ID, }) check.Args(database.InsertWorkspaceBuildParams{ @@ -1720,7 +1720,7 @@ func (s *MethodTestSuite) TestWorkspace() { })) s.Run("Stop/InsertWorkspaceBuild", s.Subtest(func(db database.Store, check *expects) { t := dbgen.Template(s.T(), db, database.Template{}) - w := dbgen.Workspace(s.T(), db, database.Workspace{ + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ TemplateID: t.ID, }) check.Args(database.InsertWorkspaceBuildParams{ @@ -1740,7 +1740,7 @@ func (s *MethodTestSuite) TestWorkspace() { v := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ TemplateID: uuid.NullUUID{UUID: t.ID}, }) - w := dbgen.Workspace(s.T(), db, database.Workspace{ + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ TemplateID: t.ID, }) check.Args(database.InsertWorkspaceBuildParams{ @@ -1766,7 +1766,7 @@ func (s *MethodTestSuite) TestWorkspace() { }) require.NoError(s.T(), err) - w := dbgen.Workspace(s.T(), db, database.Workspace{ + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ TemplateID: t.ID, }) // Assert that we do not check for template update permissions @@ -1781,7 +1781,7 @@ func (s *MethodTestSuite) TestWorkspace() { ) })) s.Run("Delete/InsertWorkspaceBuild", s.Subtest(func(db database.Store, check *expects) { - w := dbgen.Workspace(s.T(), db, database.Workspace{}) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) check.Args(database.InsertWorkspaceBuildParams{ WorkspaceID: w.ID, Transition: database.WorkspaceTransitionDelete, @@ -1789,7 +1789,7 @@ func (s *MethodTestSuite) TestWorkspace() { }).Asserts(w, policy.ActionDelete) })) s.Run("InsertWorkspaceBuildParameters", s.Subtest(func(db database.Store, check *expects) { - w := dbgen.Workspace(s.T(), db, database.Workspace{}) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: w.ID}) check.Args(database.InsertWorkspaceBuildParametersParams{ WorkspaceBuildID: b.ID, @@ -1798,7 +1798,7 @@ func (s *MethodTestSuite) TestWorkspace() { }).Asserts(w, policy.ActionUpdate) })) s.Run("UpdateWorkspace", s.Subtest(func(db database.Store, check *expects) { - w := dbgen.Workspace(s.T(), db, database.Workspace{}) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) expected := w expected.Name = "" check.Args(database.UpdateWorkspaceParams{ @@ -1806,20 +1806,20 @@ func (s *MethodTestSuite) TestWorkspace() { }).Asserts(w, policy.ActionUpdate).Returns(expected) })) s.Run("UpdateWorkspaceDormantDeletingAt", s.Subtest(func(db database.Store, check *expects) { - w := dbgen.Workspace(s.T(), db, database.Workspace{}) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) check.Args(database.UpdateWorkspaceDormantDeletingAtParams{ ID: w.ID, }).Asserts(w, policy.ActionUpdate) })) s.Run("UpdateWorkspaceAutomaticUpdates", s.Subtest(func(db database.Store, check *expects) { - w := dbgen.Workspace(s.T(), db, database.Workspace{}) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) check.Args(database.UpdateWorkspaceAutomaticUpdatesParams{ ID: w.ID, AutomaticUpdates: database.AutomaticUpdatesAlways, }).Asserts(w, policy.ActionUpdate) })) s.Run("UpdateWorkspaceAppHealthByID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) @@ -1830,13 +1830,13 @@ func (s *MethodTestSuite) TestWorkspace() { }).Asserts(ws, policy.ActionUpdate).Returns() })) s.Run("UpdateWorkspaceAutostart", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) check.Args(database.UpdateWorkspaceAutostartParams{ ID: ws.ID, }).Asserts(ws, policy.ActionUpdate).Returns() })) s.Run("UpdateWorkspaceBuildDeadlineByID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) check.Args(database.UpdateWorkspaceBuildDeadlineByIDParams{ ID: build.ID, @@ -1845,38 +1845,38 @@ func (s *MethodTestSuite) TestWorkspace() { }).Asserts(ws, policy.ActionUpdate) })) s.Run("SoftDeleteWorkspaceByID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) ws.Deleted = true check.Args(ws.ID).Asserts(ws, policy.ActionDelete).Returns() })) s.Run("UpdateWorkspaceDeletedByID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{Deleted: true}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{Deleted: true}) check.Args(database.UpdateWorkspaceDeletedByIDParams{ ID: ws.ID, Deleted: true, }).Asserts(ws, policy.ActionDelete).Returns() })) s.Run("UpdateWorkspaceLastUsedAt", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) check.Args(database.UpdateWorkspaceLastUsedAtParams{ ID: ws.ID, }).Asserts(ws, policy.ActionUpdate).Returns() })) s.Run("BatchUpdateWorkspaceLastUsedAt", s.Subtest(func(db database.Store, check *expects) { - ws1 := dbgen.Workspace(s.T(), db, database.Workspace{}) - ws2 := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws1 := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) + ws2 := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) check.Args(database.BatchUpdateWorkspaceLastUsedAtParams{ IDs: []uuid.UUID{ws1.ID, ws2.ID}, }).Asserts(rbac.ResourceWorkspace.All(), policy.ActionUpdate).Returns() })) s.Run("UpdateWorkspaceTTL", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) check.Args(database.UpdateWorkspaceTTLParams{ ID: ws.ID, }).Asserts(ws, policy.ActionUpdate).Returns() })) s.Run("GetWorkspaceByWorkspaceAppID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) @@ -1884,7 +1884,7 @@ func (s *MethodTestSuite) TestWorkspace() { check.Args(app.ID).Asserts(ws, policy.ActionRead).Returns(ws) })) s.Run("ActivityBumpWorkspace", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ID: build.JobID, Type: database.ProvisionerJobTypeWorkspaceBuild}) check.Args(database.ActivityBumpWorkspaceParams{ @@ -1893,12 +1893,12 @@ func (s *MethodTestSuite) TestWorkspace() { })) s.Run("FavoriteWorkspace", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{OwnerID: u.ID}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{OwnerID: u.ID}) check.Args(ws.ID).Asserts(ws, policy.ActionUpdate).Returns() })) s.Run("UnfavoriteWorkspace", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{OwnerID: u.ID}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{OwnerID: u.ID}) check.Args(ws.ID).Asserts(ws, policy.ActionUpdate).Returns() })) } @@ -1906,7 +1906,7 @@ func (s *MethodTestSuite) TestWorkspace() { func (s *MethodTestSuite) TestWorkspacePortSharing() { s.Run("UpsertWorkspaceAgentPortShare", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{OwnerID: u.ID}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{OwnerID: u.ID}) ps := dbgen.WorkspaceAgentPortShare(s.T(), db, database.WorkspaceAgentPortShare{WorkspaceID: ws.ID}) //nolint:gosimple // casting is not a simplification check.Args(database.UpsertWorkspaceAgentPortShareParams{ @@ -1919,7 +1919,7 @@ func (s *MethodTestSuite) TestWorkspacePortSharing() { })) s.Run("GetWorkspaceAgentPortShare", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{OwnerID: u.ID}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{OwnerID: u.ID}) ps := dbgen.WorkspaceAgentPortShare(s.T(), db, database.WorkspaceAgentPortShare{WorkspaceID: ws.ID}) check.Args(database.GetWorkspaceAgentPortShareParams{ WorkspaceID: ps.WorkspaceID, @@ -1929,13 +1929,13 @@ func (s *MethodTestSuite) TestWorkspacePortSharing() { })) s.Run("ListWorkspaceAgentPortShares", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{OwnerID: u.ID}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{OwnerID: u.ID}) ps := dbgen.WorkspaceAgentPortShare(s.T(), db, database.WorkspaceAgentPortShare{WorkspaceID: ws.ID}) check.Args(ws.ID).Asserts(ws, policy.ActionRead).Returns([]database.WorkspaceAgentPortShare{ps}) })) s.Run("DeleteWorkspaceAgentPortShare", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{OwnerID: u.ID}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{OwnerID: u.ID}) ps := dbgen.WorkspaceAgentPortShare(s.T(), db, database.WorkspaceAgentPortShare{WorkspaceID: ws.ID}) check.Args(database.DeleteWorkspaceAgentPortShareParams{ WorkspaceID: ps.WorkspaceID, @@ -1946,14 +1946,14 @@ func (s *MethodTestSuite) TestWorkspacePortSharing() { s.Run("DeleteWorkspaceAgentPortSharesByTemplate", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) t := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{OwnerID: u.ID, TemplateID: t.ID}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{OwnerID: u.ID, TemplateID: t.ID}) _ = dbgen.WorkspaceAgentPortShare(s.T(), db, database.WorkspaceAgentPortShare{WorkspaceID: ws.ID}) check.Args(t.ID).Asserts(t, policy.ActionUpdate).Returns() })) s.Run("ReduceWorkspaceAgentShareLevelToAuthenticatedByTemplate", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) t := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{OwnerID: u.ID, TemplateID: t.ID}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{OwnerID: u.ID, TemplateID: t.ID}) _ = dbgen.WorkspaceAgentPortShare(s.T(), db, database.WorkspaceAgentPortShare{WorkspaceID: ws.ID}) check.Args(t.ID).Asserts(t, policy.ActionUpdate).Returns() })) @@ -2305,7 +2305,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { }).Asserts(rbac.ResourceSystem, policy.ActionUpdate).Returns(l) })) s.Run("GetLatestWorkspaceBuildsByWorkspaceIDs", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID}) check.Args([]uuid.UUID{ws.ID}).Asserts(rbac.ResourceSystem, policy.ActionRead).Returns(slice.New(b)) })) @@ -2388,7 +2388,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { }).Asserts(rbac.ResourceSystem, policy.ActionUpdate) })) s.Run("UpdateWorkspaceBuildProvisionerStateByID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) check.Args(database.UpdateWorkspaceBuildProvisionerStateByIDParams{ ID: build.ID, @@ -2801,7 +2801,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { })) s.Run("UpsertJFrogXrayScanByWorkspaceAndAgentID", s.Subtest(func(db database.Store, check *expects) { tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{ + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ TemplateID: tpl.ID, }) check.Args(database.UpsertJFrogXrayScanByWorkspaceAndAgentIDParams{ @@ -2848,7 +2848,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { }).Asserts(rbac.ResourceSystem, policy.ActionCreate) })) s.Run("GetProvisionerJobTimingsByJobID", s.Subtest(func(db database.Store, check *expects) { - w := dbgen.Workspace(s.T(), db, database.Workspace{}) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ Type: database.ProvisionerJobTypeWorkspaceBuild, }) @@ -2857,7 +2857,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { check.Args(j.ID).Asserts(w, policy.ActionRead).Returns(t) })) s.Run("GetWorkspaceAgentScriptTimingsByBuildID", s.Subtest(func(db database.Store, check *expects) { - workspace := dbgen.Workspace(s.T(), db, database.Workspace{}) + workspace := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) job := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ Type: database.ProvisionerJobTypeWorkspaceBuild, }) diff --git a/coderd/database/dbgen/dbgen_test.go b/coderd/database/dbgen/dbgen_test.go index 04f6d38d70d00..eec6e90d5904a 100644 --- a/coderd/database/dbgen/dbgen_test.go +++ b/coderd/database/dbgen/dbgen_test.go @@ -128,8 +128,8 @@ func TestGenerator(t *testing.T) { t.Run("Workspace", func(t *testing.T) { t.Parallel() db := dbmem.New() - exp := dbgen.Workspace(t, db, database.Workspace{}) - require.Equal(t, exp, must(db.GetWorkspaceByID(context.Background(), exp.ID))) + exp := dbgen.Workspace(t, db, database.WorkspaceTable{}) + require.Equal(t, exp, must(db.GetWorkspaceByID(context.Background(), exp.ID)).WorkspaceTable()) }) t.Run("WorkspaceAgent", func(t *testing.T) { diff --git a/coderd/database/dbpurge/dbpurge_test.go b/coderd/database/dbpurge/dbpurge_test.go index 8353a1cbdcd1b..75c73700d1e4f 100644 --- a/coderd/database/dbpurge/dbpurge_test.go +++ b/coderd/database/dbpurge/dbpurge_test.go @@ -195,7 +195,7 @@ func TestDeleteOldWorkspaceAgentLogs(t *testing.T) { // Workspace A was built twice before the threshold, and never connected on // either attempt. - wsA := dbgen.Workspace(t, db, database.Workspace{Name: "a", OwnerID: user.ID, OrganizationID: org.ID, TemplateID: tmpl.ID}) + wsA := dbgen.Workspace(t, db, database.WorkspaceTable{Name: "a", OwnerID: user.ID, OrganizationID: org.ID, TemplateID: tmpl.ID}) wbA1 := mustCreateWorkspaceBuild(t, db, org, tv, wsA.ID, beforeThreshold, 1) wbA2 := mustCreateWorkspaceBuild(t, db, org, tv, wsA.ID, beforeThreshold, 2) agentA1 := mustCreateAgent(t, db, wbA1) @@ -204,7 +204,7 @@ func TestDeleteOldWorkspaceAgentLogs(t *testing.T) { mustCreateAgentLogs(ctx, t, db, agentA2, nil, "agent a2 logs should be retained") // Workspace B was built twice before the threshold. - wsB := dbgen.Workspace(t, db, database.Workspace{Name: "b", OwnerID: user.ID, OrganizationID: org.ID, TemplateID: tmpl.ID}) + wsB := dbgen.Workspace(t, db, database.WorkspaceTable{Name: "b", OwnerID: user.ID, OrganizationID: org.ID, TemplateID: tmpl.ID}) wbB1 := mustCreateWorkspaceBuild(t, db, org, tv, wsB.ID, beforeThreshold, 1) wbB2 := mustCreateWorkspaceBuild(t, db, org, tv, wsB.ID, beforeThreshold, 2) agentB1 := mustCreateAgent(t, db, wbB1) @@ -213,7 +213,7 @@ func TestDeleteOldWorkspaceAgentLogs(t *testing.T) { mustCreateAgentLogs(ctx, t, db, agentB2, &beforeThreshold, "agent b2 logs should be retained") // Workspace C was built once before the threshold, and once after. - wsC := dbgen.Workspace(t, db, database.Workspace{Name: "c", OwnerID: user.ID, OrganizationID: org.ID, TemplateID: tmpl.ID}) + wsC := dbgen.Workspace(t, db, database.WorkspaceTable{Name: "c", OwnerID: user.ID, OrganizationID: org.ID, TemplateID: tmpl.ID}) wbC1 := mustCreateWorkspaceBuild(t, db, org, tv, wsC.ID, beforeThreshold, 1) wbC2 := mustCreateWorkspaceBuild(t, db, org, tv, wsC.ID, afterThreshold, 2) agentC1 := mustCreateAgent(t, db, wbC1) @@ -222,7 +222,7 @@ func TestDeleteOldWorkspaceAgentLogs(t *testing.T) { mustCreateAgentLogs(ctx, t, db, agentC2, &afterThreshold, "agent c2 logs should be retained") // Workspace D was built twice after the threshold. - wsD := dbgen.Workspace(t, db, database.Workspace{Name: "d", OwnerID: user.ID, OrganizationID: org.ID, TemplateID: tmpl.ID}) + wsD := dbgen.Workspace(t, db, database.WorkspaceTable{Name: "d", OwnerID: user.ID, OrganizationID: org.ID, TemplateID: tmpl.ID}) wbD1 := mustCreateWorkspaceBuild(t, db, org, tv, wsD.ID, afterThreshold, 1) wbD2 := mustCreateWorkspaceBuild(t, db, org, tv, wsD.ID, afterThreshold, 2) agentD1 := mustCreateAgent(t, db, wbD1) @@ -231,7 +231,7 @@ func TestDeleteOldWorkspaceAgentLogs(t *testing.T) { mustCreateAgentLogs(ctx, t, db, agentD2, &afterThreshold, "agent d2 logs should be retained") // Workspace E was build once after threshold but never connected. - wsE := dbgen.Workspace(t, db, database.Workspace{Name: "e", OwnerID: user.ID, OrganizationID: org.ID, TemplateID: tmpl.ID}) + wsE := dbgen.Workspace(t, db, database.WorkspaceTable{Name: "e", OwnerID: user.ID, OrganizationID: org.ID, TemplateID: tmpl.ID}) wbE1 := mustCreateWorkspaceBuild(t, db, org, tv, wsE.ID, beforeThreshold, 1) agentE1 := mustCreateAgent(t, db, wbE1) mustCreateAgentLogs(ctx, t, db, agentE1, nil, "agent e1 logs should be retained") diff --git a/coderd/database/dbrollup/dbrollup_test.go b/coderd/database/dbrollup/dbrollup_test.go index 6c8e96b847b80..0c32ddc9a9c9a 100644 --- a/coderd/database/dbrollup/dbrollup_test.go +++ b/coderd/database/dbrollup/dbrollup_test.go @@ -64,7 +64,7 @@ func TestRollup_TwoInstancesUseLocking(t *testing.T) { user = dbgen.User(t, db, database.User{Name: "user1"}) tpl = dbgen.Template(t, db, database.Template{OrganizationID: org.ID, CreatedBy: user.ID}) ver = dbgen.TemplateVersion(t, db, database.TemplateVersion{OrganizationID: org.ID, TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, CreatedBy: user.ID}) - ws = dbgen.Workspace(t, db, database.Workspace{OrganizationID: org.ID, TemplateID: tpl.ID, OwnerID: user.ID}) + ws = dbgen.Workspace(t, db, database.WorkspaceTable{OrganizationID: org.ID, TemplateID: tpl.ID, OwnerID: user.ID}) job = dbgen.ProvisionerJob(t, db, ps, database.ProvisionerJob{OrganizationID: org.ID}) build = dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: job.ID, TemplateVersionID: ver.ID}) res = dbgen.WorkspaceResource(t, db, database.WorkspaceResource{JobID: build.JobID}) @@ -151,7 +151,7 @@ func TestRollupTemplateUsageStats(t *testing.T) { user = dbgen.User(t, db, database.User{Name: "user1"}) tpl = dbgen.Template(t, db, database.Template{OrganizationID: org.ID, CreatedBy: user.ID}) ver = dbgen.TemplateVersion(t, db, database.TemplateVersion{OrganizationID: org.ID, TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, CreatedBy: user.ID}) - ws = dbgen.Workspace(t, db, database.Workspace{OrganizationID: org.ID, TemplateID: tpl.ID, OwnerID: user.ID}) + ws = dbgen.Workspace(t, db, database.WorkspaceTable{OrganizationID: org.ID, TemplateID: tpl.ID, OwnerID: user.ID}) job = dbgen.ProvisionerJob(t, db, ps, database.ProvisionerJob{OrganizationID: org.ID}) build = dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: job.ID, TemplateVersionID: ver.ID}) res = dbgen.WorkspaceResource(t, db, database.WorkspaceResource{JobID: build.JobID}) diff --git a/coderd/httpmw/workspaceagent_test.go b/coderd/httpmw/workspaceagent_test.go index 0bc4b04a3589d..eae2902f537c7 100644 --- a/coderd/httpmw/workspaceagent_test.go +++ b/coderd/httpmw/workspaceagent_test.go @@ -116,7 +116,7 @@ func setup(t testing.TB, db database.Store, authToken uuid.UUID, mw func(http.Ha ActiveVersionID: templateVersion.ID, CreatedBy: user.ID, }) - workspace := dbgen.Workspace(t, db, database.Workspace{ + workspace := dbgen.Workspace(t, db, database.WorkspaceTable{ OwnerID: user.ID, OrganizationID: org.ID, TemplateID: template.ID, diff --git a/coderd/httpmw/workspaceagentparam_test.go b/coderd/httpmw/workspaceagentparam_test.go index b27c80ba94710..51e55b81e20a7 100644 --- a/coderd/httpmw/workspaceagentparam_test.go +++ b/coderd/httpmw/workspaceagentparam_test.go @@ -31,7 +31,7 @@ func TestWorkspaceAgentParam(t *testing.T) { UserID: user.ID, }) tpl = dbgen.Template(t, db, database.Template{}) - workspace = dbgen.Workspace(t, db, database.Workspace{ + workspace = dbgen.Workspace(t, db, database.WorkspaceTable{ OwnerID: user.ID, TemplateID: tpl.ID, }) diff --git a/coderd/httpmw/workspacebuildparam_test.go b/coderd/httpmw/workspacebuildparam_test.go index fb2d2f044f77f..9d49a4bd8c392 100644 --- a/coderd/httpmw/workspacebuildparam_test.go +++ b/coderd/httpmw/workspacebuildparam_test.go @@ -26,7 +26,7 @@ func TestWorkspaceBuildParam(t *testing.T) { _, token = dbgen.APIKey(t, db, database.APIKey{ UserID: user.ID, }) - workspace = dbgen.Workspace(t, db, database.Workspace{ + workspace = dbgen.Workspace(t, db, database.WorkspaceTable{ OwnerID: user.ID, }) ) diff --git a/coderd/httpmw/workspaceparam_test.go b/coderd/httpmw/workspaceparam_test.go index 54daf661c39c8..81f47d135f6ee 100644 --- a/coderd/httpmw/workspaceparam_test.go +++ b/coderd/httpmw/workspaceparam_test.go @@ -355,7 +355,7 @@ func setupWorkspaceWithAgents(t testing.TB, cfg setupConfig) (database.Store, *h _, token = dbgen.APIKey(t, db, database.APIKey{ UserID: user.ID, }) - workspace = dbgen.Workspace(t, db, database.Workspace{ + workspace = dbgen.Workspace(t, db, database.WorkspaceTable{ OwnerID: user.ID, Name: cfg.WorkspaceName, }) diff --git a/coderd/notifications/reports/generator_internal_test.go b/coderd/notifications/reports/generator_internal_test.go index a6a7f66f725cf..fcf22d80d80f9 100644 --- a/coderd/notifications/reports/generator_internal_test.go +++ b/coderd/notifications/reports/generator_internal_test.go @@ -90,7 +90,7 @@ func TestReportFailedWorkspaceBuilds(t *testing.T) { t1v1 := dbgen.TemplateVersion(t, db, database.TemplateVersion{Name: "template-1-version-1", CreatedBy: templateAdmin1.ID, OrganizationID: org.ID, TemplateID: uuid.NullUUID{UUID: t1.ID, Valid: true}, JobID: uuid.New()}) // Workspaces - w1 := dbgen.Workspace(t, db, database.Workspace{TemplateID: t1.ID, OwnerID: user1.ID, OrganizationID: org.ID}) + w1 := dbgen.Workspace(t, db, database.WorkspaceTable{TemplateID: t1.ID, OwnerID: user1.ID, OrganizationID: org.ID}) w1wb1pj := dbgen.ProvisionerJob(t, db, ps, database.ProvisionerJob{OrganizationID: org.ID, Error: jobError, ErrorCode: jobErrorCode, CompletedAt: sql.NullTime{Time: now.Add(-6 * dayDuration), Valid: true}}) _ = dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{WorkspaceID: w1.ID, BuildNumber: 1, TemplateVersionID: t1v1.ID, JobID: w1wb1pj.ID, CreatedAt: now.Add(-2 * dayDuration), Transition: database.WorkspaceTransitionStart, Reason: database.BuildReasonInitiator}) @@ -164,10 +164,10 @@ func TestReportFailedWorkspaceBuilds(t *testing.T) { t2v2 := dbgen.TemplateVersion(t, db, database.TemplateVersion{Name: "template-2-version-2", CreatedBy: templateAdmin1.ID, OrganizationID: org.ID, TemplateID: uuid.NullUUID{UUID: t2.ID, Valid: true}, JobID: uuid.New()}) // Workspaces - w1 := dbgen.Workspace(t, db, database.Workspace{TemplateID: t1.ID, OwnerID: user1.ID, OrganizationID: org.ID}) - w2 := dbgen.Workspace(t, db, database.Workspace{TemplateID: t2.ID, OwnerID: user2.ID, OrganizationID: org.ID}) - w3 := dbgen.Workspace(t, db, database.Workspace{TemplateID: t1.ID, OwnerID: user1.ID, OrganizationID: org.ID}) - w4 := dbgen.Workspace(t, db, database.Workspace{TemplateID: t2.ID, OwnerID: user2.ID, OrganizationID: org.ID}) + w1 := dbgen.Workspace(t, db, database.WorkspaceTable{TemplateID: t1.ID, OwnerID: user1.ID, OrganizationID: org.ID}) + w2 := dbgen.Workspace(t, db, database.WorkspaceTable{TemplateID: t2.ID, OwnerID: user2.ID, OrganizationID: org.ID}) + w3 := dbgen.Workspace(t, db, database.WorkspaceTable{TemplateID: t1.ID, OwnerID: user1.ID, OrganizationID: org.ID}) + w4 := dbgen.Workspace(t, db, database.WorkspaceTable{TemplateID: t2.ID, OwnerID: user2.ID, OrganizationID: org.ID}) // When: first run notifEnq.Clear() @@ -330,7 +330,7 @@ func TestReportFailedWorkspaceBuilds(t *testing.T) { t1v2 := dbgen.TemplateVersion(t, db, database.TemplateVersion{Name: "template-1-version-2", CreatedBy: templateAdmin1.ID, OrganizationID: org.ID, TemplateID: uuid.NullUUID{UUID: t1.ID, Valid: true}, JobID: uuid.New()}) // Workspaces - w1 := dbgen.Workspace(t, db, database.Workspace{TemplateID: t1.ID, OwnerID: user1.ID, OrganizationID: org.ID}) + w1 := dbgen.Workspace(t, db, database.WorkspaceTable{TemplateID: t1.ID, OwnerID: user1.ID, OrganizationID: org.ID}) // When: first run notifEnq.Clear() @@ -427,7 +427,7 @@ func TestReportFailedWorkspaceBuilds(t *testing.T) { t1v1 := dbgen.TemplateVersion(t, db, database.TemplateVersion{Name: "template-1-version-1", CreatedBy: templateAdmin1.ID, OrganizationID: org.ID, TemplateID: uuid.NullUUID{UUID: t1.ID, Valid: true}, JobID: uuid.New()}) // Workspaces - w1 := dbgen.Workspace(t, db, database.Workspace{TemplateID: t1.ID, OwnerID: user1.ID, OrganizationID: org.ID}) + w1 := dbgen.Workspace(t, db, database.WorkspaceTable{TemplateID: t1.ID, OwnerID: user1.ID, OrganizationID: org.ID}) // When: first run notifEnq.Clear() diff --git a/coderd/prometheusmetrics/insights/metricscollector_test.go b/coderd/prometheusmetrics/insights/metricscollector_test.go index 9179c9896235d..9382fa5013525 100644 --- a/coderd/prometheusmetrics/insights/metricscollector_test.go +++ b/coderd/prometheusmetrics/insights/metricscollector_test.go @@ -63,8 +63,8 @@ func TestCollectInsights(t *testing.T) { param1 = dbgen.TemplateVersionParameter(t, db, database.TemplateVersionParameter{TemplateVersionID: ver.ID, Name: "first_parameter"}) param2 = dbgen.TemplateVersionParameter(t, db, database.TemplateVersionParameter{TemplateVersionID: ver.ID, Name: "second_parameter", Type: "bool"}) param3 = dbgen.TemplateVersionParameter(t, db, database.TemplateVersionParameter{TemplateVersionID: ver.ID, Name: "third_parameter", Type: "number"}) - workspace1 = dbgen.Workspace(t, db, database.Workspace{OrganizationID: orgID, TemplateID: tpl.ID, OwnerID: user.ID}) - workspace2 = dbgen.Workspace(t, db, database.Workspace{OrganizationID: orgID, TemplateID: tpl.ID, OwnerID: user.ID}) + workspace1 = dbgen.Workspace(t, db, database.WorkspaceTable{OrganizationID: orgID, TemplateID: tpl.ID, OwnerID: user.ID}) + workspace2 = dbgen.Workspace(t, db, database.WorkspaceTable{OrganizationID: orgID, TemplateID: tpl.ID, OwnerID: user.ID}) job1 = dbgen.ProvisionerJob(t, db, ps, database.ProvisionerJob{OrganizationID: orgID}) job2 = dbgen.ProvisionerJob(t, db, ps, database.ProvisionerJob{OrganizationID: orgID}) build1 = dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{TemplateVersionID: ver.ID, WorkspaceID: workspace1.ID, JobID: job1.ID}) diff --git a/coderd/provisionerdserver/provisionerdserver_test.go b/coderd/provisionerdserver/provisionerdserver_test.go index c6c5613f97a35..e17313de92023 100644 --- a/coderd/provisionerdserver/provisionerdserver_test.go +++ b/coderd/provisionerdserver/provisionerdserver_test.go @@ -267,7 +267,7 @@ func TestAcquireJob(t *testing.T) { Required: true, Sensitive: false, }) - workspace := dbgen.Workspace(t, db, database.Workspace{ + workspace := dbgen.Workspace(t, db, database.WorkspaceTable{ TemplateID: template.ID, OwnerID: user.ID, OrganizationID: pd.OrganizationID, @@ -1263,7 +1263,7 @@ func TestCompleteJob(t *testing.T) { Valid: true, } } - workspace := dbgen.Workspace(t, db, database.Workspace{ + workspace := dbgen.Workspace(t, db, database.WorkspaceTable{ TemplateID: template.ID, Ttl: workspaceTTL, OwnerID: user.ID, @@ -1622,7 +1622,7 @@ func TestNotifications(t *testing.T) { template, err := db.GetTemplateByID(ctx, template.ID) require.NoError(t, err) file := dbgen.File(t, db, database.File{CreatedBy: user.ID}) - workspace := dbgen.Workspace(t, db, database.Workspace{ + workspace := dbgen.Workspace(t, db, database.WorkspaceTable{ TemplateID: template.ID, OwnerID: user.ID, OrganizationID: pd.OrganizationID, @@ -1740,7 +1740,7 @@ func TestNotifications(t *testing.T) { OrganizationID: pd.OrganizationID, }) file := dbgen.File(t, db, database.File{CreatedBy: user.ID}) - workspace := dbgen.Workspace(t, db, database.Workspace{ + workspace := dbgen.Workspace(t, db, database.WorkspaceTable{ TemplateID: template.ID, OwnerID: user.ID, OrganizationID: pd.OrganizationID, @@ -1822,7 +1822,7 @@ func TestNotifications(t *testing.T) { template := dbgen.Template(t, db, database.Template{ Name: "template", DisplayName: "William's Template", Provisioner: database.ProvisionerTypeEcho, OrganizationID: pd.OrganizationID, }) - workspace := dbgen.Workspace(t, db, database.Workspace{ + workspace := dbgen.Workspace(t, db, database.WorkspaceTable{ TemplateID: template.ID, OwnerID: user.ID, OrganizationID: pd.OrganizationID, }) version := dbgen.TemplateVersion(t, db, database.TemplateVersion{ diff --git a/coderd/schedule/autostop_test.go b/coderd/schedule/autostop_test.go index 0c4c072438537..e28ce3579cd4c 100644 --- a/coderd/schedule/autostop_test.go +++ b/coderd/schedule/autostop_test.go @@ -561,7 +561,7 @@ func TestCalculateAutoStop(t *testing.T) { Valid: true, } } - workspace := dbgen.Workspace(t, db, database.Workspace{ + workspace := dbgen.Workspace(t, db, database.WorkspaceTable{ TemplateID: template.ID, OrganizationID: org.ID, OwnerID: user.ID, diff --git a/coderd/telemetry/telemetry_test.go b/coderd/telemetry/telemetry_test.go index fd9f4752bff51..908bcd657ee4f 100644 --- a/coderd/telemetry/telemetry_test.go +++ b/coderd/telemetry/telemetry_test.go @@ -50,7 +50,7 @@ func TestTelemetry(t *testing.T) { }) _ = dbgen.TemplateVersion(t, db, database.TemplateVersion{}) user := dbgen.User(t, db, database.User{}) - _ = dbgen.Workspace(t, db, database.Workspace{}) + _ = dbgen.Workspace(t, db, database.WorkspaceTable{}) _ = dbgen.WorkspaceApp(t, db, database.WorkspaceApp{ SharingLevel: database.AppSharingLevelOwner, Health: database.WorkspaceAppHealthDisabled, diff --git a/coderd/unhanger/detector_test.go b/coderd/unhanger/detector_test.go index 28bb2575b9ee7..b1bf374881d37 100644 --- a/coderd/unhanger/detector_test.go +++ b/coderd/unhanger/detector_test.go @@ -133,7 +133,7 @@ func TestDetectorHungWorkspaceBuild(t *testing.T) { }, CreatedBy: user.ID, }) - workspace = dbgen.Workspace(t, db, database.Workspace{ + workspace = dbgen.Workspace(t, db, database.WorkspaceTable{ OwnerID: user.ID, OrganizationID: org.ID, TemplateID: template.ID, @@ -255,7 +255,7 @@ func TestDetectorHungWorkspaceBuildNoOverrideState(t *testing.T) { }, CreatedBy: user.ID, }) - workspace = dbgen.Workspace(t, db, database.Workspace{ + workspace = dbgen.Workspace(t, db, database.WorkspaceTable{ OwnerID: user.ID, OrganizationID: org.ID, TemplateID: template.ID, @@ -377,7 +377,7 @@ func TestDetectorHungWorkspaceBuildNoOverrideStateIfNoExistingBuild(t *testing.T }, CreatedBy: user.ID, }) - workspace = dbgen.Workspace(t, db, database.Workspace{ + workspace = dbgen.Workspace(t, db, database.WorkspaceTable{ OwnerID: user.ID, OrganizationID: org.ID, TemplateID: template.ID, diff --git a/coderd/users.go b/coderd/users.go index 78b88ba892426..73ac5c4212a42 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -1461,15 +1461,6 @@ func userOrganizationIDs(ctx context.Context, api *API, user database.User) ([]u return member.OrganizationIDs, nil } -func userByID(id uuid.UUID, users []database.User) (database.User, bool) { - for _, user := range users { - if id == user.ID { - return user, true - } - } - return database.User{}, false -} - func convertAPIKey(k database.APIKey) codersdk.APIKey { return codersdk.APIKey{ ID: k.ID, diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index 57579ea12daad..0b8fc0789d527 100644 --- a/coderd/workspacebuilds.go +++ b/coderd/workspacebuilds.go @@ -641,7 +641,7 @@ type workspaceBuildsData struct { logSources []database.WorkspaceAgentLogSource } -func (api *API) workspaceBuildsData(ctx context.Context, workspaces []database.Workspace, workspaceBuilds []database.WorkspaceBuild) (workspaceBuildsData, error) { +func (api *API) workspaceBuildsData(ctx context.Context, workspaceBuilds []database.WorkspaceBuild) (workspaceBuildsData, error) { jobIDs := make([]uuid.UUID, 0, len(workspaceBuilds)) for _, build := range workspaceBuilds { jobIDs = append(jobIDs, build.JobID) diff --git a/coderd/workspacestats/activitybump_test.go b/coderd/workspacestats/activitybump_test.go index 3abb46b7ab343..50c22042d6491 100644 --- a/coderd/workspacestats/activitybump_test.go +++ b/coderd/workspacestats/activitybump_test.go @@ -191,7 +191,7 @@ func Test_ActivityBumpWorkspace(t *testing.T) { ActiveVersionID: templateVersion.ID, CreatedBy: user.ID, }) - ws = dbgen.Workspace(t, db, database.Workspace{ + ws = dbgen.Workspace(t, db, database.WorkspaceTable{ OwnerID: user.ID, OrganizationID: org.ID, TemplateID: template.ID, diff --git a/coderd/workspacestats/batcher_internal_test.go b/coderd/workspacestats/batcher_internal_test.go index 2f7a25b152127..029adb507ab98 100644 --- a/coderd/workspacestats/batcher_internal_test.go +++ b/coderd/workspacestats/batcher_internal_test.go @@ -189,7 +189,7 @@ func setupDeps(t *testing.T, store database.Store, ps pubsub.Pubsub) deps { OrganizationID: org.ID, ActiveVersionID: tv.ID, }) - ws := dbgen.Workspace(t, store, database.Workspace{ + ws := dbgen.Workspace(t, store, database.WorkspaceTable{ TemplateID: tpl.ID, OwnerID: user.ID, OrganizationID: org.ID, diff --git a/coderd/workspacestats/tracker_test.go b/coderd/workspacestats/tracker_test.go index 99e9f9503b645..4b5115fd143e9 100644 --- a/coderd/workspacestats/tracker_test.go +++ b/coderd/workspacestats/tracker_test.go @@ -149,7 +149,7 @@ func TestTracker_MultipleInstances(t *testing.T) { numWorkspaces := 10 w := make([]dbfake.WorkspaceResponse, numWorkspaces) for i := 0; i < numWorkspaces; i++ { - wr := dbfake.WorkspaceBuild(t, db, database.Workspace{ + wr := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OwnerID: owner.UserID, OrganizationID: owner.OrganizationID, LastUsedAt: now, diff --git a/enterprise/coderd/appearance_test.go b/enterprise/coderd/appearance_test.go index e3563aa882e5a..8550f13904e2d 100644 --- a/enterprise/coderd/appearance_test.go +++ b/enterprise/coderd/appearance_test.go @@ -148,7 +148,7 @@ func TestAnnouncementBanners(t *testing.T) { err := client.UpdateAppearance(ctx, cfg) require.NoError(t, err) - r := dbfake.WorkspaceBuild(t, store, database.Workspace{ + r := dbfake.WorkspaceBuild(t, store, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent().Do() diff --git a/enterprise/coderd/workspaces_test.go b/enterprise/coderd/workspaces_test.go index dc685c46cec41..239c7ae377102 100644 --- a/enterprise/coderd/workspaces_test.go +++ b/enterprise/coderd/workspaces_test.go @@ -449,7 +449,7 @@ func TestWorkspaceAutobuild(t *testing.T) { TimeTilDormantMillis: inactiveTTL.Milliseconds(), }) - resp := dbfake.WorkspaceBuild(t, db, database.Workspace{ + resp := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, TemplateID: template.ID, @@ -1260,18 +1260,18 @@ func TestWorkspacesFiltering(t *testing.T) { CreatedBy: owner.UserID, }).Do() - dormantWS1 := dbfake.WorkspaceBuild(t, db, database.Workspace{ + dormantWS1 := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OwnerID: templateAdmin.ID, OrganizationID: owner.OrganizationID, }).Do().Workspace - dormantWS2 := dbfake.WorkspaceBuild(t, db, database.Workspace{ + dormantWS2 := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OwnerID: templateAdmin.ID, OrganizationID: owner.OrganizationID, TemplateID: resp.Template.ID, }).Do().Workspace - _ = dbfake.WorkspaceBuild(t, db, database.Workspace{ + _ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OwnerID: templateAdmin.ID, OrganizationID: owner.OrganizationID, TemplateID: resp.Template.ID, @@ -1448,7 +1448,7 @@ func TestResolveAutostart(t *testing.T) { client, member := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID) - workspace := dbfake.WorkspaceBuild(t, db, database.Workspace{ + workspace := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OwnerID: member.ID, OrganizationID: owner.OrganizationID, TemplateID: version1.Template.ID, diff --git a/support/support_test.go b/support/support_test.go index cdd62ceeb8f9b..1a088eb734185 100644 --- a/support/support_test.go +++ b/support/support_test.go @@ -199,7 +199,7 @@ func setupWorkspaceAndAgent(ctx context.Context, t *testing.T, client *codersdk. CreatedBy: user.UserID, }). Do() - wbr := dbfake.WorkspaceBuild(t, db, database.Workspace{ + wbr := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, TemplateID: tv.Template.ID, From b231af9df95c01069537319b5ade76801e923f95 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 18 Oct 2024 09:07:28 -0500 Subject: [PATCH 09/23] fixup audit track and workspacebuildData call --- coderd/database/queries.sql.go | 2 +- coderd/database/queries/workspaces.sql | 2 +- coderd/workspacebuilds.go | 6 +++--- coderd/workspaces.go | 2 +- docs/admin/security/audit-logs.md | 1 + enterprise/audit/table.go | 2 +- 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 4eb7c251f40a5..33a9730b51ca6 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -14960,7 +14960,7 @@ WHERE -- Filter by owner_name AND CASE WHEN $8 :: text != '' THEN - workspaces.owner_id = (SELECT id FROM users WHERE lower(username) = lower($8) AND deleted = false) + workspaces.owner_id = (SELECT id FROM users WHERE lower(owner_username) = lower($8) AND deleted = false) ELSE true END -- Filter by template_name diff --git a/coderd/database/queries/workspaces.sql b/coderd/database/queries/workspaces.sql index 9d6311cb97eed..32cc7adeb5d9c 100644 --- a/coderd/database/queries/workspaces.sql +++ b/coderd/database/queries/workspaces.sql @@ -233,7 +233,7 @@ WHERE -- Filter by owner_name AND CASE WHEN @owner_username :: text != '' THEN - workspaces.owner_id = (SELECT id FROM users WHERE lower(username) = lower(@owner_username) AND deleted = false) + workspaces.owner_id = (SELECT id FROM users WHERE lower(owner_username) = lower(@owner_username) AND deleted = false) ELSE true END -- Filter by template_name diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index 0b8fc0789d527..3515bc4a944b5 100644 --- a/coderd/workspacebuilds.go +++ b/coderd/workspacebuilds.go @@ -46,7 +46,7 @@ func (api *API) workspaceBuild(rw http.ResponseWriter, r *http.Request) { workspaceBuild := httpmw.WorkspaceBuildParam(r) workspace := httpmw.WorkspaceParam(r) - data, err := api.workspaceBuildsData(ctx, []database.Workspace{workspace}, []database.WorkspaceBuild{workspaceBuild}) + data, err := api.workspaceBuildsData(ctx, []database.WorkspaceBuild{workspaceBuild}) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ Message: "Internal error getting workspace build data.", @@ -179,7 +179,7 @@ func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) { return } - data, err := api.workspaceBuildsData(ctx, []database.Workspace{workspace}, workspaceBuilds) + data, err := api.workspaceBuildsData(ctx, workspaceBuilds) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ Message: "Internal error getting workspace build data.", @@ -268,7 +268,7 @@ func (api *API) workspaceBuildByBuildNumber(rw http.ResponseWriter, r *http.Requ return } - data, err := api.workspaceBuildsData(ctx, []database.Workspace{workspace}, []database.WorkspaceBuild{workspaceBuild}) + data, err := api.workspaceBuildsData(ctx, []database.WorkspaceBuild{workspaceBuild}) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ Message: "Internal error getting workspace build data.", diff --git a/coderd/workspaces.go b/coderd/workspaces.go index a901209094984..394a728472b0d 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -1780,7 +1780,7 @@ func (api *API) workspaceData(ctx context.Context, workspaces []database.Workspa return workspaceData{}, xerrors.Errorf("get workspace builds: %w", err) } - data, err := api.workspaceBuildsData(ctx, workspaces, builds) + data, err := api.workspaceBuildsData(ctx, builds) if err != nil { return workspaceData{}, xerrors.Errorf("get workspace builds data: %w", err) } diff --git a/docs/admin/security/audit-logs.md b/docs/admin/security/audit-logs.md index b22055ff18b5a..f8711259dce13 100644 --- a/docs/admin/security/audit-logs.md +++ b/docs/admin/security/audit-logs.md @@ -29,6 +29,7 @@ We track the following resources: | Workspace
create, write, delete |
FieldTracked
automatic_updatestrue
autostart_scheduletrue
created_atfalse
deletedfalse
deleting_attrue
dormant_attrue
favoritetrue
idtrue
last_used_atfalse
nametrue
organization_idfalse
owner_idtrue
template_idtrue
ttltrue
updated_atfalse
| | WorkspaceBuild
start, stop |
FieldTracked
build_numberfalse
created_atfalse
daily_costfalse
deadlinefalse
idfalse
initiator_by_avatar_urlfalse
initiator_by_usernamefalse
initiator_idfalse
job_idfalse
max_deadlinefalse
provisioner_statefalse
reasonfalse
template_version_idtrue
transitionfalse
updated_atfalse
workspace_idfalse
| | WorkspaceProxy
|
FieldTracked
created_attrue
deletedfalse
derp_enabledtrue
derp_onlytrue
display_nametrue
icontrue
idtrue
nametrue
region_idtrue
token_hashed_secrettrue
updated_atfalse
urltrue
versiontrue
wildcard_hostnametrue
| +| WorkspaceTable
|
FieldTracked
automatic_updatestrue
autostart_scheduletrue
created_atfalse
deletedfalse
deleting_attrue
dormant_attrue
favoritetrue
idtrue
last_used_atfalse
nametrue
organization_idfalse
owner_idtrue
template_idtrue
ttltrue
updated_atfalse
| diff --git a/enterprise/audit/table.go b/enterprise/audit/table.go index baa9f33b18786..2de2d918dc0aa 100644 --- a/enterprise/audit/table.go +++ b/enterprise/audit/table.go @@ -149,7 +149,7 @@ var auditableResourcesTypes = map[any]map[string]Action{ "one_time_passcode_expires_at": ActionTrack, "must_reset_password": ActionTrack, }, - &database.Workspace{}: { + &database.WorkspaceTable{}: { "id": ActionTrack, "created_at": ActionIgnore, // Never changes. "updated_at": ActionIgnore, // Changes, but is implicit and not helpful in a diff. From ba01ba0dd593e4c47b7ef5f77aef43190d2e07fc Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 18 Oct 2024 09:08:23 -0500 Subject: [PATCH 10/23] bump migration number --- ...e_with_names.down.sql => 000267_workspace_with_names.down.sql} | 0 ...space_with_names.up.sql => 000267_workspace_with_names.up.sql} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename coderd/database/migrations/{000266_workspace_with_names.down.sql => 000267_workspace_with_names.down.sql} (100%) rename coderd/database/migrations/{000266_workspace_with_names.up.sql => 000267_workspace_with_names.up.sql} (100%) diff --git a/coderd/database/migrations/000266_workspace_with_names.down.sql b/coderd/database/migrations/000267_workspace_with_names.down.sql similarity index 100% rename from coderd/database/migrations/000266_workspace_with_names.down.sql rename to coderd/database/migrations/000267_workspace_with_names.down.sql diff --git a/coderd/database/migrations/000266_workspace_with_names.up.sql b/coderd/database/migrations/000267_workspace_with_names.up.sql similarity index 100% rename from coderd/database/migrations/000266_workspace_with_names.up.sql rename to coderd/database/migrations/000267_workspace_with_names.up.sql From b216efd651580361b418ed54405e42a0e8991bfd Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 18 Oct 2024 09:20:38 -0500 Subject: [PATCH 11/23] fix more tests --- coderd/database/dbauthz/dbauthz_test.go | 23 ++++++++----------- .../000267_workspace_with_names.down.sql | 1 + coderd/httpmw/workspaceagent_test.go | 2 +- coderd/httpmw/workspacebuildparam_test.go | 2 +- .../provisionerdserver/provisionerdserver.go | 2 +- .../provisionerdserver_test.go | 12 +++++----- coderd/schedule/autostop.go | 2 +- .../workspacestats/batcher_internal_test.go | 2 +- enterprise/coderd/jfrog_test.go | 2 +- enterprise/coderd/schedule/template.go | 2 +- testutil/reflect.go | 2 ++ 11 files changed, 26 insertions(+), 26 deletions(-) diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 68f6ff6fc67ac..038df287d7b55 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -1655,10 +1655,7 @@ func (s *MethodTestSuite) TestWorkspace() { build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) - check.Args(agt.ID).Asserts(ws, policy.ActionRead).Returns(database.Workspace{ - Workspace: ws, - TemplateName: tpl.Name, - }) + check.Args(agt.ID).Asserts(ws, policy.ActionRead) })) s.Run("GetWorkspaceAgentsInLatestBuildByWorkspaceID", s.Subtest(func(db database.Store, check *expects) { tpl := dbgen.Template(s.T(), db, database.Template{}) @@ -1676,7 +1673,7 @@ func (s *MethodTestSuite) TestWorkspace() { OwnerID: ws.OwnerID, Deleted: ws.Deleted, Name: ws.Name, - }).Asserts(ws, policy.ActionRead).Returns(ws) + }).Asserts(ws, policy.ActionRead) })) s.Run("GetWorkspaceResourceByID", s.Subtest(func(db database.Store, check *expects) { ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) @@ -1881,7 +1878,7 @@ func (s *MethodTestSuite) TestWorkspace() { res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) app := dbgen.WorkspaceApp(s.T(), db, database.WorkspaceApp{AgentID: agt.ID}) - check.Args(app.ID).Asserts(ws, policy.ActionRead).Returns(ws) + check.Args(app.ID).Asserts(ws, policy.ActionRead) })) s.Run("ActivityBumpWorkspace", s.Subtest(func(db database.Store, check *expects) { ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) @@ -2457,13 +2454,13 @@ func (s *MethodTestSuite) TestSystemFunctions() { Asserts(tpl, policy.ActionRead).Errors(sql.ErrNoRows) })) s.Run("GetWorkspaceAppsByAgentIDs", s.Subtest(func(db database.Store, check *expects) { - aWs := dbgen.Workspace(s.T(), db, database.Workspace{}) + aWs := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) aBuild := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: aWs.ID, JobID: uuid.New()}) aRes := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: aBuild.JobID}) aAgt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: aRes.ID}) a := dbgen.WorkspaceApp(s.T(), db, database.WorkspaceApp{AgentID: aAgt.ID}) - bWs := dbgen.Workspace(s.T(), db, database.Workspace{}) + bWs := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) bBuild := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: bWs.ID, JobID: uuid.New()}) bRes := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: bBuild.JobID}) bAgt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: bRes.ID}) @@ -2478,7 +2475,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { v := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, JobID: uuid.New()}) tJob := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ID: v.JobID, Type: database.ProvisionerJobTypeTemplateVersionImport}) - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) wJob := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ID: build.JobID, Type: database.ProvisionerJobTypeWorkspaceBuild}) check.Args([]uuid.UUID{tJob.ID, wJob.ID}). @@ -2486,7 +2483,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { Returns([]database.WorkspaceResource{}) })) s.Run("GetWorkspaceResourceMetadataByResourceIDs", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) _ = dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ID: build.JobID, Type: database.ProvisionerJobTypeWorkspaceBuild}) a := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) @@ -2495,7 +2492,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { Asserts(rbac.ResourceSystem, policy.ActionRead) })) s.Run("GetWorkspaceAgentsByResourceIDs", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) @@ -2529,7 +2526,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { }).Asserts(rbac.ResourceSystem, policy.ActionCreate) })) s.Run("UpdateWorkspaceAgentConnectionByID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) @@ -2772,7 +2769,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { check.Args(uuid.New()).Asserts(rbac.ResourceSystem, policy.ActionRead) })) s.Run("GetJFrogXrayScanByWorkspaceAndAgentID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.Workspace{}) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) agent := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{}) err := db.UpsertJFrogXrayScanByWorkspaceAndAgentID(context.Background(), database.UpsertJFrogXrayScanByWorkspaceAndAgentIDParams{ diff --git a/coderd/database/migrations/000267_workspace_with_names.down.sql b/coderd/database/migrations/000267_workspace_with_names.down.sql index e69de29bb2d1d..dd9c23c2f36c5 100644 --- a/coderd/database/migrations/000267_workspace_with_names.down.sql +++ b/coderd/database/migrations/000267_workspace_with_names.down.sql @@ -0,0 +1 @@ +DROP VIEW workspaces_expanded; diff --git a/coderd/httpmw/workspaceagent_test.go b/coderd/httpmw/workspaceagent_test.go index eae2902f537c7..8d79b6ddbdbb9 100644 --- a/coderd/httpmw/workspaceagent_test.go +++ b/coderd/httpmw/workspaceagent_test.go @@ -97,7 +97,7 @@ func TestWorkspaceAgent(t *testing.T) { }) } -func setup(t testing.TB, db database.Store, authToken uuid.UUID, mw func(http.Handler) http.Handler) (*http.Request, http.Handler, database.Workspace, database.TemplateVersion) { +func setup(t testing.TB, db database.Store, authToken uuid.UUID, mw func(http.Handler) http.Handler) (*http.Request, http.Handler, database.WorkspaceTable, database.TemplateVersion) { t.Helper() org := dbgen.Organization(t, db, database.Organization{}) user := dbgen.User(t, db, database.User{ diff --git a/coderd/httpmw/workspacebuildparam_test.go b/coderd/httpmw/workspacebuildparam_test.go index 9d49a4bd8c392..e4bd4d10dafb2 100644 --- a/coderd/httpmw/workspacebuildparam_test.go +++ b/coderd/httpmw/workspacebuildparam_test.go @@ -20,7 +20,7 @@ import ( func TestWorkspaceBuildParam(t *testing.T) { t.Parallel() - setupAuthentication := func(db database.Store) (*http.Request, database.Workspace) { + setupAuthentication := func(db database.Store) (*http.Request, database.WorkspaceTable) { var ( user = dbgen.User(t, db, database.User{}) _, token = dbgen.APIKey(t, db, database.APIKey{ diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index e81aa02f0c264..0a4198423e403 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -1406,7 +1406,7 @@ func (s *server) CompleteJob(ctx context.Context, completed *proto.CompletedJob) TemplateScheduleStore: *s.TemplateScheduleStore.Load(), UserQuietHoursScheduleStore: *s.UserQuietHoursScheduleStore.Load(), Now: now, - Workspace: workspace, + Workspace: workspace.WorkspaceTable(), // Allowed to be the empty string. WorkspaceAutostart: workspace.AutostartSchedule.String, }) diff --git a/coderd/provisionerdserver/provisionerdserver_test.go b/coderd/provisionerdserver/provisionerdserver_test.go index e17313de92023..baa53b92d74e2 100644 --- a/coderd/provisionerdserver/provisionerdserver_test.go +++ b/coderd/provisionerdserver/provisionerdserver_test.go @@ -1263,7 +1263,7 @@ func TestCompleteJob(t *testing.T) { Valid: true, } } - workspace := dbgen.Workspace(t, db, database.WorkspaceTable{ + workspaceTable := dbgen.Workspace(t, db, database.WorkspaceTable{ TemplateID: template.ID, Ttl: workspaceTTL, OwnerID: user.ID, @@ -1278,7 +1278,7 @@ func TestCompleteJob(t *testing.T) { JobID: uuid.New(), }) build := dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{ - WorkspaceID: workspace.ID, + WorkspaceID: workspaceTable.ID, TemplateVersionID: version.ID, Transition: c.transition, Reason: database.BuildReasonInitiator, @@ -1331,7 +1331,7 @@ func TestCompleteJob(t *testing.T) { <-publishedWorkspace <-publishedLogs - workspace, err = db.GetWorkspaceByID(ctx, workspace.ID) + workspace, err := db.GetWorkspaceByID(ctx, workspaceTable.ID) require.NoError(t, err) require.Equal(t, c.transition == database.WorkspaceTransitionDelete, workspace.Deleted) @@ -1622,7 +1622,7 @@ func TestNotifications(t *testing.T) { template, err := db.GetTemplateByID(ctx, template.ID) require.NoError(t, err) file := dbgen.File(t, db, database.File{CreatedBy: user.ID}) - workspace := dbgen.Workspace(t, db, database.WorkspaceTable{ + workspaceTable := dbgen.Workspace(t, db, database.WorkspaceTable{ TemplateID: template.ID, OwnerID: user.ID, OrganizationID: pd.OrganizationID, @@ -1636,7 +1636,7 @@ func TestNotifications(t *testing.T) { JobID: uuid.New(), }) build := dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{ - WorkspaceID: workspace.ID, + WorkspaceID: workspaceTable.ID, TemplateVersionID: version.ID, InitiatorID: initiator.ID, Transition: database.WorkspaceTransitionDelete, @@ -1674,7 +1674,7 @@ func TestNotifications(t *testing.T) { }) require.NoError(t, err) - workspace, err = db.GetWorkspaceByID(ctx, workspace.ID) + workspace, err := db.GetWorkspaceByID(ctx, workspaceTable.ID) require.NoError(t, err) require.True(t, workspace.Deleted) diff --git a/coderd/schedule/autostop.go b/coderd/schedule/autostop.go index 1651b3f64aa9c..88529d26b3b78 100644 --- a/coderd/schedule/autostop.go +++ b/coderd/schedule/autostop.go @@ -51,7 +51,7 @@ type CalculateAutostopParams struct { WorkspaceAutostart string Now time.Time - Workspace database.Workspace + Workspace database.WorkspaceTable } type AutostopTime struct { diff --git a/coderd/workspacestats/batcher_internal_test.go b/coderd/workspacestats/batcher_internal_test.go index 029adb507ab98..3e106f07e4e2f 100644 --- a/coderd/workspacestats/batcher_internal_test.go +++ b/coderd/workspacestats/batcher_internal_test.go @@ -162,7 +162,7 @@ type deps struct { Agent database.WorkspaceAgent Template database.Template User database.User - Workspace database.Workspace + Workspace database.WorkspaceTable } // setupDeps sets up a set of test dependencies. diff --git a/enterprise/coderd/jfrog_test.go b/enterprise/coderd/jfrog_test.go index fd47f80b3ee92..9403bf4ec3c19 100644 --- a/enterprise/coderd/jfrog_test.go +++ b/enterprise/coderd/jfrog_test.go @@ -85,7 +85,7 @@ func TestJFrogXrayScan(t *testing.T) { memberClient, member := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID) - wsResp := dbfake.WorkspaceBuild(t, db, database.Workspace{ + wsResp := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: owner.OrganizationID, OwnerID: member.ID, }).WithAgent().Do() diff --git a/enterprise/coderd/schedule/template.go b/enterprise/coderd/schedule/template.go index 7ac428f102e4d..626e296d6a3e8 100644 --- a/enterprise/coderd/schedule/template.go +++ b/enterprise/coderd/schedule/template.go @@ -296,7 +296,7 @@ func (s *EnterpriseTemplateScheduleStore) updateWorkspaceBuild(ctx context.Conte UserQuietHoursScheduleStore: *s.UserQuietHoursScheduleStore.Load(), // Use the job completion time as the time we calculate autostop from. Now: job.CompletedAt.Time, - Workspace: workspace, + Workspace: workspace.WorkspaceTable(), WorkspaceAutostart: workspace.AutostartSchedule.String, }) if err != nil { diff --git a/testutil/reflect.go b/testutil/reflect.go index b1e9b37899fda..0ad1be1770907 100644 --- a/testutil/reflect.go +++ b/testutil/reflect.go @@ -71,6 +71,8 @@ func populateValue(v reflect.Value, r *Random) (reflect.Value, error) { case reflect.TypeOf(time.Time{}): v.Set(reflect.ValueOf(time.Date(2020, 5, 2, 5, 19, 21, 30, time.UTC))) return v, nil + default: + // Go to Kind instead } switch v.Kind() { From d13fd1031991368f1434d4bcc7e050df3274b349 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 18 Oct 2024 09:22:53 -0500 Subject: [PATCH 12/23] fmt --- coderd/autobuild/lifecycle_executor.go | 1 - testutil/reflect.go | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/coderd/autobuild/lifecycle_executor.go b/coderd/autobuild/lifecycle_executor.go index b83d0522d4f9f..400f0406aee0e 100644 --- a/coderd/autobuild/lifecycle_executor.go +++ b/coderd/autobuild/lifecycle_executor.go @@ -241,7 +241,6 @@ func (e *Executor) runOnce(t time.Time) Stats { Valid: true, }, }) - if err != nil { return xerrors.Errorf("update workspace dormant deleting at: %w", err) } diff --git a/testutil/reflect.go b/testutil/reflect.go index 0ad1be1770907..ef6eb3013d471 100644 --- a/testutil/reflect.go +++ b/testutil/reflect.go @@ -128,7 +128,7 @@ func populateValue(v reflect.Value, r *Random) (reflect.Value, error) { s.Index(0).Set(sv) s.Index(1).Set(sv) - //reflect.AppendSlice(s, sv) + // reflect.AppendSlice(s, sv) return s, nil case reflect.Uintptr, reflect.UnsafePointer, reflect.Chan, reflect.Func, reflect.Interface: From d48c231abda07ad29b48b7da8b7a8402b67d0461 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 18 Oct 2024 09:32:50 -0500 Subject: [PATCH 13/23] continue fixing references to Workspace/WorkspaceTable --- cli/agent_test.go | 10 +++++----- cli/favorite_test.go | 2 +- cli/gitssh_test.go | 2 +- cli/list_test.go | 4 ++-- cli/portforward_test.go | 4 ++-- cli/schedule_test.go | 8 ++++---- cli/ssh_test.go | 10 +++++----- cli/start_test.go | 4 ++-- cli/state_test.go | 6 +++--- cli/support_test.go | 6 +++--- cli/vscodessh_test.go | 2 +- coderd/agentapi/stats_test.go | 29 +++++++++-------------------- enterprise/coderd/jfrog_test.go | 2 +- 13 files changed, 39 insertions(+), 50 deletions(-) diff --git a/cli/agent_test.go b/cli/agent_test.go index 5d37f2c54c9d4..ceebdf3ce0964 100644 --- a/cli/agent_test.go +++ b/cli/agent_test.go @@ -35,7 +35,7 @@ func TestWorkspaceAgent(t *testing.T) { client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }). @@ -71,7 +71,7 @@ func TestWorkspaceAgent(t *testing.T) { AzureCertificates: certificates, }) user := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { @@ -110,7 +110,7 @@ func TestWorkspaceAgent(t *testing.T) { AWSCertificates: certificates, }) user := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { @@ -151,7 +151,7 @@ func TestWorkspaceAgent(t *testing.T) { }) owner := coderdtest.CreateFirstUser(t, client) member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: owner.OrganizationID, OwnerID: memberUser.ID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { @@ -205,7 +205,7 @@ func TestWorkspaceAgent(t *testing.T) { client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent().Do() diff --git a/cli/favorite_test.go b/cli/favorite_test.go index 5cdf5e765c6cf..0668f03361e2d 100644 --- a/cli/favorite_test.go +++ b/cli/favorite_test.go @@ -19,7 +19,7 @@ func TestFavoriteUnfavorite(t *testing.T) { client, db = coderdtest.NewWithDatabase(t, nil) owner = coderdtest.CreateFirstUser(t, client) memberClient, member = coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) - ws = dbfake.WorkspaceBuild(t, db, database.Workspace{OwnerID: member.ID, OrganizationID: owner.OrganizationID}).Do() + ws = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{OwnerID: member.ID, OrganizationID: owner.OrganizationID}).Do() ) inv, root := clitest.New(t, "favorite", ws.Workspace.Name) diff --git a/cli/gitssh_test.go b/cli/gitssh_test.go index 83b873dec914e..6d574ae651aec 100644 --- a/cli/gitssh_test.go +++ b/cli/gitssh_test.go @@ -48,7 +48,7 @@ func prepareTestGitSSH(ctx context.Context, t *testing.T) (*agentsdk.Client, str require.NoError(t, err) // setup template - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, }).WithAgent().Do() diff --git a/cli/list_test.go b/cli/list_test.go index 82d372bd350aa..37f2f36f79278 100644 --- a/cli/list_test.go +++ b/cli/list_test.go @@ -26,7 +26,7 @@ func TestList(t *testing.T) { owner := coderdtest.CreateFirstUser(t, client) member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) // setup template - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: owner.OrganizationID, OwnerID: memberUser.ID, }).WithAgent().Do() @@ -54,7 +54,7 @@ func TestList(t *testing.T) { client, db := coderdtest.NewWithDatabase(t, nil) owner := coderdtest.CreateFirstUser(t, client) member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) - _ = dbfake.WorkspaceBuild(t, db, database.Workspace{ + _ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: owner.OrganizationID, OwnerID: memberUser.ID, }).WithAgent().Do() diff --git a/cli/portforward_test.go b/cli/portforward_test.go index edef520c23dc6..29fccafb20ac1 100644 --- a/cli/portforward_test.go +++ b/cli/portforward_test.go @@ -290,12 +290,12 @@ func TestPortForward(t *testing.T) { // runAgent creates a fake workspace and starts an agent locally for that // workspace. The agent will be cleaned up on test completion. // nolint:unused -func runAgent(t *testing.T, client *codersdk.Client, owner uuid.UUID, db database.Store) database.Workspace { +func runAgent(t *testing.T, client *codersdk.Client, owner uuid.UUID, db database.Store) database.WorkspaceTable { user, err := client.User(context.Background(), codersdk.Me) require.NoError(t, err, "specified user does not exist") require.Greater(t, len(user.OrganizationIDs), 0, "user has no organizations") orgID := user.OrganizationIDs[0] - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: orgID, OwnerID: owner, }).WithAgent().Do() diff --git a/cli/schedule_test.go b/cli/schedule_test.go index 11e0171417c04..bf18155be293a 100644 --- a/cli/schedule_test.go +++ b/cli/schedule_test.go @@ -38,7 +38,7 @@ func setupTestSchedule(t *testing.T, sched *cron.Schedule) (ownerClient, memberC memberClient, memberUser := coderdtest.CreateAnotherUserMutators(t, ownerClient, owner.OrganizationID, nil, func(r *codersdk.CreateUserRequestWithOrgs) { r.Username = "testuser2" // ensure deterministic ordering }) - _ = dbfake.WorkspaceBuild(t, db, database.Workspace{ + _ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ Name: "a-owner", OwnerID: owner.UserID, OrganizationID: owner.OrganizationID, @@ -46,19 +46,19 @@ func setupTestSchedule(t *testing.T, sched *cron.Schedule) (ownerClient, memberC Ttl: sql.NullInt64{Int64: 8 * time.Hour.Nanoseconds(), Valid: true}, }).WithAgent().Do() - _ = dbfake.WorkspaceBuild(t, db, database.Workspace{ + _ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ Name: "b-owner", OwnerID: owner.UserID, OrganizationID: owner.OrganizationID, AutostartSchedule: sql.NullString{String: sched.String(), Valid: true}, }).WithAgent().Do() - _ = dbfake.WorkspaceBuild(t, db, database.Workspace{ + _ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ Name: "c-member", OwnerID: memberUser.ID, OrganizationID: owner.OrganizationID, Ttl: sql.NullInt64{Int64: 8 * time.Hour.Nanoseconds(), Valid: true}, }).WithAgent().Do() - _ = dbfake.WorkspaceBuild(t, db, database.Workspace{ + _ = dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ Name: "d-member", OwnerID: memberUser.ID, OrganizationID: owner.OrganizationID, diff --git a/cli/ssh_test.go b/cli/ssh_test.go index d000e090a44e4..c2a14c90e39e6 100644 --- a/cli/ssh_test.go +++ b/cli/ssh_test.go @@ -53,14 +53,14 @@ import ( "github.com/coder/coder/v2/testutil" ) -func setupWorkspaceForAgent(t *testing.T, mutations ...func([]*proto.Agent) []*proto.Agent) (*codersdk.Client, database.Workspace, string) { +func setupWorkspaceForAgent(t *testing.T, mutations ...func([]*proto.Agent) []*proto.Agent) (*codersdk.Client, database.WorkspaceTable, string) { t.Helper() client, store := coderdtest.NewWithDatabase(t, nil) client.SetLogger(slogtest.Make(t, nil).Named("client").Leveled(slog.LevelDebug)) first := coderdtest.CreateFirstUser(t, client) userClient, user := coderdtest.CreateAnotherUser(t, client, first.OrganizationID) - r := dbfake.WorkspaceBuild(t, store, database.Workspace{ + r := dbfake.WorkspaceBuild(t, store, database.WorkspaceTable{ OrganizationID: first.OrganizationID, OwnerID: user.ID, }).WithAgent(mutations...).Do() @@ -260,7 +260,7 @@ func TestSSH(t *testing.T) { client.SetLogger(slogtest.Make(t, nil).Named("client").Leveled(slog.LevelDebug)) first := coderdtest.CreateFirstUser(t, client) userClient, user := coderdtest.CreateAnotherUser(t, client, first.OrganizationID) - r := dbfake.WorkspaceBuild(t, store, database.Workspace{ + r := dbfake.WorkspaceBuild(t, store, database.WorkspaceTable{ OrganizationID: first.OrganizationID, OwnerID: user.ID, }).WithAgent().Do() @@ -763,7 +763,7 @@ func TestSSH(t *testing.T) { client.SetLogger(slogtest.Make(t, nil).Named("client").Leveled(slog.LevelDebug)) first := coderdtest.CreateFirstUser(t, client) userClient, user := coderdtest.CreateAnotherUser(t, client, first.OrganizationID) - r := dbfake.WorkspaceBuild(t, store, database.Workspace{ + r := dbfake.WorkspaceBuild(t, store, database.WorkspaceTable{ OrganizationID: first.OrganizationID, OwnerID: user.ID, }).WithAgent().Do() @@ -1370,7 +1370,7 @@ func TestSSH(t *testing.T) { admin.SetLogger(slogtest.Make(t, nil).Named("client").Leveled(slog.LevelDebug)) first := coderdtest.CreateFirstUser(t, admin) client, user := coderdtest.CreateAnotherUser(t, admin, first.OrganizationID) - r := dbfake.WorkspaceBuild(t, store, database.Workspace{ + r := dbfake.WorkspaceBuild(t, store, database.WorkspaceTable{ OrganizationID: first.OrganizationID, OwnerID: user.ID, }).WithAgent().Do() diff --git a/cli/start_test.go b/cli/start_test.go index e9809ff4bc4ff..da5fb74cacf72 100644 --- a/cli/start_test.go +++ b/cli/start_test.go @@ -390,7 +390,7 @@ func TestStart_AlreadyRunning(t *testing.T) { client, db := coderdtest.NewWithDatabase(t, nil) owner := coderdtest.CreateFirstUser(t, client) memberClient, member := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OwnerID: member.ID, OrganizationID: owner.OrganizationID, }).Do() @@ -417,7 +417,7 @@ func TestStart_Starting(t *testing.T) { client := coderdtest.New(t, &coderdtest.Options{Pubsub: ps, Database: store}) owner := coderdtest.CreateFirstUser(t, client) memberClient, member := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) - r := dbfake.WorkspaceBuild(t, store, database.Workspace{ + r := dbfake.WorkspaceBuild(t, store, database.WorkspaceTable{ OwnerID: member.ID, OrganizationID: owner.OrganizationID, }). diff --git a/cli/state_test.go b/cli/state_test.go index 08f2c96d14f7b..44b92b2c7960d 100644 --- a/cli/state_test.go +++ b/cli/state_test.go @@ -28,7 +28,7 @@ func TestStatePull(t *testing.T) { owner := coderdtest.CreateFirstUser(t, client) templateAdmin, taUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleTemplateAdmin()) wantState := []byte("some state") - r := dbfake.WorkspaceBuild(t, store, database.Workspace{ + r := dbfake.WorkspaceBuild(t, store, database.WorkspaceTable{ OrganizationID: owner.OrganizationID, OwnerID: taUser.ID, }). @@ -49,7 +49,7 @@ func TestStatePull(t *testing.T) { owner := coderdtest.CreateFirstUser(t, client) templateAdmin, taUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleTemplateAdmin()) wantState := []byte("some state") - r := dbfake.WorkspaceBuild(t, store, database.Workspace{ + r := dbfake.WorkspaceBuild(t, store, database.WorkspaceTable{ OrganizationID: owner.OrganizationID, OwnerID: taUser.ID, }). @@ -69,7 +69,7 @@ func TestStatePull(t *testing.T) { owner := coderdtest.CreateFirstUser(t, client) _, taUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleTemplateAdmin()) wantState := []byte("some state") - r := dbfake.WorkspaceBuild(t, store, database.Workspace{ + r := dbfake.WorkspaceBuild(t, store, database.WorkspaceTable{ OrganizationID: owner.OrganizationID, OwnerID: taUser.ID, }). diff --git a/cli/support_test.go b/cli/support_test.go index 6fe8f015c3f2b..274454acb7a48 100644 --- a/cli/support_test.go +++ b/cli/support_test.go @@ -53,7 +53,7 @@ func TestSupportBundle(t *testing.T) { DeploymentValues: dc.Values, }) owner := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: owner.OrganizationID, OwnerID: owner.UserID, }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { @@ -132,7 +132,7 @@ func TestSupportBundle(t *testing.T) { DeploymentValues: dc.Values, }) admin := coderdtest.CreateFirstUser(t, client) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: admin.OrganizationID, OwnerID: admin.UserID, }).Do() // without agent! @@ -151,7 +151,7 @@ func TestSupportBundle(t *testing.T) { client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) memberClient, member := coderdtest.CreateAnotherUser(t, client, user.OrganizationID) - r := dbfake.WorkspaceBuild(t, db, database.Workspace{ + r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: member.ID, }).WithAgent().Do() diff --git a/cli/vscodessh_test.go b/cli/vscodessh_test.go index f80b6b0b6029e..9ef2ab912a206 100644 --- a/cli/vscodessh_test.go +++ b/cli/vscodessh_test.go @@ -41,7 +41,7 @@ func TestVSCodeSSH(t *testing.T) { admin.SetLogger(slogtest.Make(t, nil).Named("client").Leveled(slog.LevelDebug)) first := coderdtest.CreateFirstUser(t, admin) client, user := coderdtest.CreateAnotherUser(t, admin, first.OrganizationID) - r := dbfake.WorkspaceBuild(t, store, database.Workspace{ + r := dbfake.WorkspaceBuild(t, store, database.WorkspaceTable{ OrganizationID: first.OrganizationID, OwnerID: user.ID, }).WithAgent().Do() diff --git a/coderd/agentapi/stats_test.go b/coderd/agentapi/stats_test.go index 57534208be110..d2c8e4f163df5 100644 --- a/coderd/agentapi/stats_test.go +++ b/coderd/agentapi/stats_test.go @@ -40,10 +40,11 @@ func TestUpdateStates(t *testing.T) { Name: "tpl", } workspace = database.Workspace{ - ID: uuid.New(), - OwnerID: user.ID, - TemplateID: template.ID, - Name: "xyz", + ID: uuid.New(), + OwnerID: user.ID, + TemplateID: template.ID, + Name: "xyz", + TemplateName: template.Name, } agent = database.WorkspaceAgent{ ID: uuid.New(), @@ -127,10 +128,7 @@ func TestUpdateStates(t *testing.T) { } // Workspace gets fetched. - dbM.EXPECT().GetWorkspaceByAgentID(gomock.Any(), agent.ID).Return(database.GetWorkspaceByAgentIDRow{ - Workspace: workspace, - TemplateName: template.Name, - }, nil) + dbM.EXPECT().GetWorkspaceByAgentID(gomock.Any(), agent.ID).Return(workspace, nil) // We expect an activity bump because ConnectionCount > 0. dbM.EXPECT().ActivityBumpWorkspace(gomock.Any(), database.ActivityBumpWorkspaceParams{ @@ -225,10 +223,7 @@ func TestUpdateStates(t *testing.T) { } // Workspace gets fetched. - dbM.EXPECT().GetWorkspaceByAgentID(gomock.Any(), agent.ID).Return(database.GetWorkspaceByAgentIDRow{ - Workspace: workspace, - TemplateName: template.Name, - }, nil) + dbM.EXPECT().GetWorkspaceByAgentID(gomock.Any(), agent.ID).Return(workspace, nil) // Workspace last used at gets bumped. dbM.EXPECT().UpdateWorkspaceLastUsedAt(gomock.Any(), database.UpdateWorkspaceLastUsedAtParams{ @@ -350,10 +345,7 @@ func TestUpdateStates(t *testing.T) { } // Workspace gets fetched. - dbM.EXPECT().GetWorkspaceByAgentID(gomock.Any(), agent.ID).Return(database.GetWorkspaceByAgentIDRow{ - Workspace: workspace, - TemplateName: template.Name, - }, nil) + dbM.EXPECT().GetWorkspaceByAgentID(gomock.Any(), agent.ID).Return(workspace, nil) // We expect an activity bump because ConnectionCount > 0. However, the // next autostart time will be set on the bump. @@ -461,10 +453,7 @@ func TestUpdateStates(t *testing.T) { } // Workspace gets fetched. - dbM.EXPECT().GetWorkspaceByAgentID(gomock.Any(), agent.ID).Return(database.GetWorkspaceByAgentIDRow{ - Workspace: workspace, - TemplateName: template.Name, - }, nil) + dbM.EXPECT().GetWorkspaceByAgentID(gomock.Any(), agent.ID).Return(workspace, nil) // We expect an activity bump because ConnectionCount > 0. dbM.EXPECT().ActivityBumpWorkspace(gomock.Any(), database.ActivityBumpWorkspaceParams{ diff --git a/enterprise/coderd/jfrog_test.go b/enterprise/coderd/jfrog_test.go index 9403bf4ec3c19..a9841a6d92067 100644 --- a/enterprise/coderd/jfrog_test.go +++ b/enterprise/coderd/jfrog_test.go @@ -29,7 +29,7 @@ func TestJFrogXrayScan(t *testing.T) { tac, ta := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID, rbac.RoleTemplateAdmin()) - wsResp := dbfake.WorkspaceBuild(t, db, database.Workspace{ + wsResp := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: owner.OrganizationID, OwnerID: ta.ID, }).WithAgent().Do() From 8be63e729f9de88a262498ca975b885e8aadfedb Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 18 Oct 2024 09:37:02 -0500 Subject: [PATCH 14/23] linting: --- testutil/reflect.go | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/testutil/reflect.go b/testutil/reflect.go index ef6eb3013d471..0a8887479a20d 100644 --- a/testutil/reflect.go +++ b/testutil/reflect.go @@ -1,9 +1,10 @@ package testutil import ( - "fmt" "reflect" "time" + + "golang.org/x/xerrors" ) type Random struct { @@ -35,12 +36,12 @@ func PopulateStruct(s interface{}, r *Random) error { v := reflect.ValueOf(s) if v.Kind() != reflect.Ptr || v.IsNil() { - return fmt.Errorf("s must be a non-nil pointer") + return xerrors.Errorf("s must be a non-nil pointer") } v = v.Elem() if v.Kind() != reflect.Struct { - return fmt.Errorf("s must be a pointer to a struct") + return xerrors.Errorf("s must be a pointer to a struct") } t := v.Type() @@ -55,7 +56,7 @@ func PopulateStruct(s interface{}, r *Random) error { nv, err := populateValue(fieldValue, r) if err != nil { - return fmt.Errorf("%s : %w", fieldName, err) + return xerrors.Errorf("%s : %w", fieldName, err) } v.Field(i).Set(nv) } @@ -96,7 +97,7 @@ func populateValue(v reflect.Value, r *Random) (reflect.Value, error) { for i := 0; i < v.Len(); i++ { nv, err := populateValue(v.Index(i), r) if err != nil { - return v, fmt.Errorf("array index %d : %w", i, err) + return v, xerrors.Errorf("array index %d : %w", i, err) } v.Index(i).Set(nv) } @@ -108,11 +109,11 @@ func populateValue(v reflect.Value, r *Random) (reflect.Value, error) { kv := reflect.New(v.Type().Elem()) k, err = populateValue(k, r) if err != nil { - return v, fmt.Errorf("map key : %w", err) + return v, xerrors.Errorf("map key : %w", err) } kv, err = populateValue(kv, r) if err != nil { - return v, fmt.Errorf("map value : %w", err) + return v, xerrors.Errorf("map value : %w", err) } m.SetMapIndex(k, kv) @@ -123,7 +124,7 @@ func populateValue(v reflect.Value, r *Random) (reflect.Value, error) { s := reflect.MakeSlice(v.Type(), 2, 2) sv, err := populateValue(reflect.New(v.Type().Elem()), r) if err != nil { - return v, fmt.Errorf("slice value : %w", err) + return v, xerrors.Errorf("slice value : %w", err) } s.Index(0).Set(sv) @@ -133,9 +134,9 @@ func populateValue(v reflect.Value, r *Random) (reflect.Value, error) { return s, nil case reflect.Uintptr, reflect.UnsafePointer, reflect.Chan, reflect.Func, reflect.Interface: // Unsupported - return v, fmt.Errorf("%s is not supported", v.Kind()) + return v, xerrors.Errorf("%s is not supported", v.Kind()) default: - return v, fmt.Errorf("unsupported kind %s", v.Kind()) + return v, xerrors.Errorf("unsupported kind %s", v.Kind()) } return v, nil } From a80a01dfd97601cd297803fa11a01f939e6c886c Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 18 Oct 2024 10:15:08 -0500 Subject: [PATCH 15/23] make gen --- coderd/database/dump.sql | 4 ++-- coderd/database/modelmethods.go | 2 +- coderd/database/queries.sql.go | 16 ++++++++-------- coderd/database/queries/workspaces.sql | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index c4e909a6ce0ed..3a9a5a7a2d8f6 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -1717,8 +1717,8 @@ CREATE VIEW workspaces_expanded AS workspaces.deleting_at, workspaces.automatic_updates, workspaces.favorite, - COALESCE(visible_users.avatar_url, ''::text) AS owner_avatar_url, - COALESCE(visible_users.username, ''::text) AS owner_username, + visible_users.avatar_url AS owner_avatar_url, + visible_users.username AS owner_username, organizations.name AS organization_name, organizations.display_name AS organization_display_name, organizations.icon AS organization_icon, diff --git a/coderd/database/modelmethods.go b/coderd/database/modelmethods.go index cabf36419e894..12c89fb44397a 100644 --- a/coderd/database/modelmethods.go +++ b/coderd/database/modelmethods.go @@ -193,7 +193,7 @@ func (gm GroupMember) RBACObject() rbac.Object { } // WorkspaceTable converts a Workspace to it's reduced version. -// A more generalized solution is to use json marshalling to +// A more generalized solution is to use json marshaling to // consistently keep these two structs in sync. // That would be a lot of overhead, and a more costly unit test is // written to make sure these match up. diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 33a9730b51ca6..2e5959edba625 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -3356,7 +3356,7 @@ func (q *sqlQuerier) GetJFrogXrayScanByWorkspaceAndAgentID(ctx context.Context, } const upsertJFrogXrayScanByWorkspaceAndAgentID = `-- name: UpsertJFrogXrayScanByWorkspaceAndAgentID :exec -INSERT INTO +INSERT INTO jfrog_xray_scans ( agent_id, workspace_id, @@ -3365,7 +3365,7 @@ INSERT INTO medium, results_url ) -VALUES +VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (agent_id, workspace_id) DO UPDATE SET critical = $3, high = $4, medium = $5, results_url = $6 @@ -6175,7 +6175,7 @@ FROM provisioner_keys WHERE organization_id = $1 -AND +AND lower(name) = lower($2) ` @@ -6291,10 +6291,10 @@ WHERE AND -- exclude reserved built-in key id != '00000000-0000-0000-0000-000000000001'::uuid -AND +AND -- exclude reserved user-auth key id != '00000000-0000-0000-0000-000000000002'::uuid -AND +AND -- exclude reserved psk key id != '00000000-0000-0000-0000-000000000003'::uuid ` @@ -7976,7 +7976,7 @@ func (q *sqlQuerier) GetTailnetTunnelPeerIDs(ctx context.Context, srcID uuid.UUI } const updateTailnetPeerStatusByCoordinator = `-- name: UpdateTailnetPeerStatusByCoordinator :exec -UPDATE +UPDATE tailnet_peers SET status = $2 @@ -12424,7 +12424,7 @@ WITH agent_stats AS ( coalesce((PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY connection_median_latency_ms)), -1)::FLOAT AS workspace_connection_latency_95 FROM workspace_agent_stats -- The greater than 0 is to support legacy agents that don't report connection_median_latency_ms. - WHERE workspace_agent_stats.created_at > $1 AND connection_median_latency_ms > 0 + WHERE workspace_agent_stats.created_at > $1 AND connection_median_latency_ms > 0 GROUP BY user_id, agent_id, workspace_id, template_id ), latest_agent_stats AS ( SELECT @@ -15062,7 +15062,7 @@ WHERE latest_build_canceled_at IS NULL AND latest_build_error IS NULL AND latest_build_transition = 'start'::workspace_transition) DESC, - LOWER(username) ASC, + LOWER(owner_username) ASC, LOWER(name) ASC LIMIT CASE diff --git a/coderd/database/queries/workspaces.sql b/coderd/database/queries/workspaces.sql index 32cc7adeb5d9c..e7896c68fcb8a 100644 --- a/coderd/database/queries/workspaces.sql +++ b/coderd/database/queries/workspaces.sql @@ -335,7 +335,7 @@ WHERE latest_build_canceled_at IS NULL AND latest_build_error IS NULL AND latest_build_transition = 'start'::workspace_transition) DESC, - LOWER(username) ASC, + LOWER(owner_username) ASC, LOWER(name) ASC LIMIT CASE From 5ad6a58f339b72be6a4f24cbdd02815f12e99f5f Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 18 Oct 2024 10:30:14 -0500 Subject: [PATCH 16/23] sql spaces... --- coderd/database/queries.sql.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 2e5959edba625..283732a4f22d3 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -3356,7 +3356,7 @@ func (q *sqlQuerier) GetJFrogXrayScanByWorkspaceAndAgentID(ctx context.Context, } const upsertJFrogXrayScanByWorkspaceAndAgentID = `-- name: UpsertJFrogXrayScanByWorkspaceAndAgentID :exec -INSERT INTO +INSERT INTO jfrog_xray_scans ( agent_id, workspace_id, @@ -3365,7 +3365,7 @@ INSERT INTO medium, results_url ) -VALUES +VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (agent_id, workspace_id) DO UPDATE SET critical = $3, high = $4, medium = $5, results_url = $6 @@ -6175,7 +6175,7 @@ FROM provisioner_keys WHERE organization_id = $1 -AND +AND lower(name) = lower($2) ` @@ -6291,10 +6291,10 @@ WHERE AND -- exclude reserved built-in key id != '00000000-0000-0000-0000-000000000001'::uuid -AND +AND -- exclude reserved user-auth key id != '00000000-0000-0000-0000-000000000002'::uuid -AND +AND -- exclude reserved psk key id != '00000000-0000-0000-0000-000000000003'::uuid ` @@ -7976,7 +7976,7 @@ func (q *sqlQuerier) GetTailnetTunnelPeerIDs(ctx context.Context, srcID uuid.UUI } const updateTailnetPeerStatusByCoordinator = `-- name: UpdateTailnetPeerStatusByCoordinator :exec -UPDATE +UPDATE tailnet_peers SET status = $2 @@ -12424,7 +12424,7 @@ WITH agent_stats AS ( coalesce((PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY connection_median_latency_ms)), -1)::FLOAT AS workspace_connection_latency_95 FROM workspace_agent_stats -- The greater than 0 is to support legacy agents that don't report connection_median_latency_ms. - WHERE workspace_agent_stats.created_at > $1 AND connection_median_latency_ms > 0 + WHERE workspace_agent_stats.created_at > $1 AND connection_median_latency_ms > 0 GROUP BY user_id, agent_id, workspace_id, template_id ), latest_agent_stats AS ( SELECT From 9f6f5ee0f2c7daa6bbb8947d82f41e9ab27ac04d Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 18 Oct 2024 10:46:05 -0500 Subject: [PATCH 17/23] make gen --- coderd/database/models.go | 2 +- coderd/database/querier.go | 2 +- coderd/database/queries.sql.go | 14 +++++++++++--- coderd/database/queries/workspaces.sql | 12 ++++++++++-- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/coderd/database/models.go b/coderd/database/models.go index 0794546af7a22..1207587d46529 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.25.0 package database diff --git a/coderd/database/querier.go b/coderd/database/querier.go index d8c442439735d..fcb58a7d6e305 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.25.0 package database diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 283732a4f22d3..45cbef3f5e1d8 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.25.0 package database @@ -15095,11 +15095,19 @@ WHERE '0001-01-01 00:00:00+00'::timestamptz, -- deleting_at 'never'::automatic_updates, -- automatic_updates false, -- favorite - -- Extra columns added to ` + "`" + `filtered_workspaces` + "`" + ` + '', -- owner_avatar_url + '', -- owner_username + '', -- organization_name + '', -- organization_display_name + '', -- organization_icon + '', -- organization_description '', -- template_name + '', -- template_display_name + '', -- template_icon + '', -- template_description + -- Extra columns added to ` + "`" + `filtered_workspaces` + "`" + ` '00000000-0000-0000-0000-000000000000'::uuid, -- template_version_id '', -- template_version_name - '', -- username '0001-01-01 00:00:00+00'::timestamptz, -- latest_build_completed_at, '0001-01-01 00:00:00+00'::timestamptz, -- latest_build_canceled_at, '', -- latest_build_error diff --git a/coderd/database/queries/workspaces.sql b/coderd/database/queries/workspaces.sql index e7896c68fcb8a..08e795d7a2402 100644 --- a/coderd/database/queries/workspaces.sql +++ b/coderd/database/queries/workspaces.sql @@ -368,11 +368,19 @@ WHERE '0001-01-01 00:00:00+00'::timestamptz, -- deleting_at 'never'::automatic_updates, -- automatic_updates false, -- favorite - -- Extra columns added to `filtered_workspaces` + '', -- owner_avatar_url + '', -- owner_username + '', -- organization_name + '', -- organization_display_name + '', -- organization_icon + '', -- organization_description '', -- template_name + '', -- template_display_name + '', -- template_icon + '', -- template_description + -- Extra columns added to `filtered_workspaces` '00000000-0000-0000-0000-000000000000'::uuid, -- template_version_id '', -- template_version_name - '', -- username '0001-01-01 00:00:00+00'::timestamptz, -- latest_build_completed_at, '0001-01-01 00:00:00+00'::timestamptz, -- latest_build_canceled_at, '', -- latest_build_error From c48f32786eef015e362677e3e094296f2c2bdb26 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 18 Oct 2024 11:10:19 -0500 Subject: [PATCH 18/23] fix audit panic --- coderd/audit/request.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/coderd/audit/request.go b/coderd/audit/request.go index adaf3ce1f573c..88b637384eeda 100644 --- a/coderd/audit/request.go +++ b/coderd/audit/request.go @@ -82,7 +82,7 @@ func ResourceTarget[T Auditable](tgt T) string { return typed.Name case database.User: return typed.Username - case database.Workspace: + case database.WorkspaceTable: return typed.Name case database.WorkspaceBuild: // this isn't used @@ -133,7 +133,7 @@ func ResourceID[T Auditable](tgt T) uuid.UUID { return typed.ID case database.User: return typed.ID - case database.Workspace: + case database.WorkspaceTable: return typed.ID case database.WorkspaceBuild: return typed.ID @@ -181,7 +181,7 @@ func ResourceType[T Auditable](tgt T) database.ResourceType { return database.ResourceTypeTemplateVersion case database.User: return database.ResourceTypeUser - case database.Workspace: + case database.WorkspaceTable: return database.ResourceTypeWorkspace case database.WorkspaceBuild: return database.ResourceTypeWorkspaceBuild @@ -225,7 +225,7 @@ func ResourceRequiresOrgID[T Auditable]() bool { switch any(tgt).(type) { case database.Template, database.TemplateVersion: return true - case database.Workspace, database.WorkspaceBuild: + case database.WorkspaceTable, database.WorkspaceBuild: return true case database.AuditableGroup: return true From 81a8aa214605c31d95e82f5cf8794730b0cf9f28 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 18 Oct 2024 11:24:20 -0500 Subject: [PATCH 19/23] fix audit test --- enterprise/audit/diff_internal_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enterprise/audit/diff_internal_test.go b/enterprise/audit/diff_internal_test.go index 08a7153c72930..d5c191c8907fa 100644 --- a/enterprise/audit/diff_internal_test.go +++ b/enterprise/audit/diff_internal_test.go @@ -393,7 +393,7 @@ func Test_diff(t *testing.T) { { name: "NullSchedules", left: audit.Empty[database.WorkspaceTable](), - right: database.Workspace{ + right: database.WorkspaceTable{ ID: uuid.UUID{1}, CreatedAt: time.Now(), UpdatedAt: time.Now(), From 50638c7b5c2c1ce160e008d8c957b7a941dd8db7 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Fri, 18 Oct 2024 11:27:30 -0500 Subject: [PATCH 20/23] populate sdk workspace --- coderd/database/dbauthz/dbauthz_test.go | 2 +- coderd/database/modelmethods.go | 40 +++++++++++++++---------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 038df287d7b55..6a34e88104ce1 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -123,7 +123,7 @@ func TestNew(t *testing.T) { w, err := az.GetWorkspaceByID(ctx, exp.ID) require.NoError(t, err, "must not error") - require.Equal(t, exp, w, "must be equal") + require.Equal(t, exp, w.WorkspaceTable(), "must be equal") rec.AssertActor(t, subj, rec.Pair(policy.ActionRead, exp)) require.NoError(t, rec.AllAsserted(), "should only be 1 rbac call") diff --git a/coderd/database/modelmethods.go b/coderd/database/modelmethods.go index 12c89fb44397a..a74ddf29bfcf9 100644 --- a/coderd/database/modelmethods.go +++ b/coderd/database/modelmethods.go @@ -413,21 +413,31 @@ func ConvertWorkspaceRows(rows []GetWorkspacesRow) []Workspace { workspaces := make([]Workspace, len(rows)) for i, r := range rows { workspaces[i] = Workspace{ - ID: r.ID, - CreatedAt: r.CreatedAt, - UpdatedAt: r.UpdatedAt, - OwnerID: r.OwnerID, - OrganizationID: r.OrganizationID, - TemplateID: r.TemplateID, - Deleted: r.Deleted, - Name: r.Name, - AutostartSchedule: r.AutostartSchedule, - Ttl: r.Ttl, - LastUsedAt: r.LastUsedAt, - DormantAt: r.DormantAt, - DeletingAt: r.DeletingAt, - AutomaticUpdates: r.AutomaticUpdates, - Favorite: r.Favorite, + ID: r.ID, + CreatedAt: r.CreatedAt, + UpdatedAt: r.UpdatedAt, + OwnerID: r.OwnerID, + OrganizationID: r.OrganizationID, + TemplateID: r.TemplateID, + Deleted: r.Deleted, + Name: r.Name, + AutostartSchedule: r.AutostartSchedule, + Ttl: r.Ttl, + LastUsedAt: r.LastUsedAt, + DormantAt: r.DormantAt, + DeletingAt: r.DeletingAt, + AutomaticUpdates: r.AutomaticUpdates, + Favorite: r.Favorite, + OwnerAvatarUrl: r.OwnerAvatarUrl, + OwnerUsername: r.OwnerUsername, + OrganizationName: r.OrganizationName, + OrganizationDisplayName: r.OrganizationDisplayName, + OrganizationIcon: r.OrganizationIcon, + OrganizationDescription: r.OrganizationDescription, + TemplateName: r.TemplateName, + TemplateDisplayName: r.TemplateDisplayName, + TemplateIcon: r.TemplateIcon, + TemplateDescription: r.TemplateDescription, } } From 6e448d8f144e4f9cdaff2160a1d654302c56c409 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 22 Oct 2024 09:05:27 -0500 Subject: [PATCH 21/23] rebase fixes --- ...th_names.down.sql => 000269_workspace_with_names.down.sql} | 0 ...e_with_names.up.sql => 000269_workspace_with_names.up.sql} | 0 docs/admin/security/audit-logs.md | 1 - testutil/reflect.go | 4 +++- 4 files changed, 3 insertions(+), 2 deletions(-) rename coderd/database/migrations/{000267_workspace_with_names.down.sql => 000269_workspace_with_names.down.sql} (100%) rename coderd/database/migrations/{000267_workspace_with_names.up.sql => 000269_workspace_with_names.up.sql} (100%) diff --git a/coderd/database/migrations/000267_workspace_with_names.down.sql b/coderd/database/migrations/000269_workspace_with_names.down.sql similarity index 100% rename from coderd/database/migrations/000267_workspace_with_names.down.sql rename to coderd/database/migrations/000269_workspace_with_names.down.sql diff --git a/coderd/database/migrations/000267_workspace_with_names.up.sql b/coderd/database/migrations/000269_workspace_with_names.up.sql similarity index 100% rename from coderd/database/migrations/000267_workspace_with_names.up.sql rename to coderd/database/migrations/000269_workspace_with_names.up.sql diff --git a/docs/admin/security/audit-logs.md b/docs/admin/security/audit-logs.md index f8711259dce13..602710289261f 100644 --- a/docs/admin/security/audit-logs.md +++ b/docs/admin/security/audit-logs.md @@ -26,7 +26,6 @@ We track the following resources: | Template
write, delete |
FieldTracked
active_version_idtrue
activity_bumptrue
allow_user_autostarttrue
allow_user_autostoptrue
allow_user_cancel_workspace_jobstrue
autostart_block_days_of_weektrue
autostop_requirement_days_of_weektrue
autostop_requirement_weekstrue
created_atfalse
created_bytrue
created_by_avatar_urlfalse
created_by_usernamefalse
default_ttltrue
deletedfalse
deprecatedtrue
descriptiontrue
display_nametrue
failure_ttltrue
group_acltrue
icontrue
idtrue
max_port_sharing_leveltrue
nametrue
organization_display_namefalse
organization_iconfalse
organization_idfalse
organization_namefalse
provisionertrue
require_active_versiontrue
time_til_dormanttrue
time_til_dormant_autodeletetrue
updated_atfalse
user_acltrue
| | TemplateVersion
create, write |
FieldTracked
archivedtrue
created_atfalse
created_bytrue
created_by_avatar_urlfalse
created_by_usernamefalse
external_auth_providersfalse
idtrue
job_idfalse
messagefalse
nametrue
organization_idfalse
readmetrue
template_idtrue
updated_atfalse
| | User
create, write, delete |
FieldTracked
avatar_urlfalse
created_atfalse
deletedtrue
emailtrue
github_com_user_idfalse
hashed_one_time_passcodefalse
hashed_passwordtrue
idtrue
last_seen_atfalse
login_typetrue
must_reset_passwordtrue
nametrue
one_time_passcode_expires_attrue
quiet_hours_scheduletrue
rbac_rolestrue
statustrue
theme_preferencefalse
updated_atfalse
usernametrue
| -| Workspace
create, write, delete |
FieldTracked
automatic_updatestrue
autostart_scheduletrue
created_atfalse
deletedfalse
deleting_attrue
dormant_attrue
favoritetrue
idtrue
last_used_atfalse
nametrue
organization_idfalse
owner_idtrue
template_idtrue
ttltrue
updated_atfalse
| | WorkspaceBuild
start, stop |
FieldTracked
build_numberfalse
created_atfalse
daily_costfalse
deadlinefalse
idfalse
initiator_by_avatar_urlfalse
initiator_by_usernamefalse
initiator_idfalse
job_idfalse
max_deadlinefalse
provisioner_statefalse
reasonfalse
template_version_idtrue
transitionfalse
updated_atfalse
workspace_idfalse
| | WorkspaceProxy
|
FieldTracked
created_attrue
deletedfalse
derp_enabledtrue
derp_onlytrue
display_nametrue
icontrue
idtrue
nametrue
region_idtrue
token_hashed_secrettrue
updated_atfalse
urltrue
versiontrue
wildcard_hostnametrue
| | WorkspaceTable
|
FieldTracked
automatic_updatestrue
autostart_scheduletrue
created_atfalse
deletedfalse
deleting_attrue
dormant_attrue
favoritetrue
idtrue
last_used_atfalse
nametrue
organization_idfalse
owner_idtrue
template_idtrue
ttltrue
updated_atfalse
| diff --git a/testutil/reflect.go b/testutil/reflect.go index 0a8887479a20d..a776ac98e20a0 100644 --- a/testutil/reflect.go +++ b/testutil/reflect.go @@ -14,6 +14,7 @@ type Random struct { Uint func() uint64 Float func() float64 Complex func() complex128 + Time func() time.Time } func NewRandom() *Random { @@ -25,6 +26,7 @@ func NewRandom() *Random { Uint: func() uint64 { return 126 }, Float: func() float64 { return 3.14 }, Complex: func() complex128 { return 6.24 }, + Time: func() time.Time { return time.Date(2020, 5, 2, 5, 19, 21, 30, time.UTC) }, } } @@ -70,7 +72,7 @@ func populateValue(v reflect.Value, r *Random) (reflect.Value, error) { // Handle some special cases switch v.Type() { case reflect.TypeOf(time.Time{}): - v.Set(reflect.ValueOf(time.Date(2020, 5, 2, 5, 19, 21, 30, time.UTC))) + v.Set(reflect.ValueOf(r.Time())) return v, nil default: // Go to Kind instead From 05ce1ae9b26af48b01e2669b0c9f5c12a0f3b8f1 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 22 Oct 2024 09:10:11 -0500 Subject: [PATCH 22/23] fix workspace reference --- cli/agent_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/agent_test.go b/cli/agent_test.go index ceebdf3ce0964..0a948c0c84e9a 100644 --- a/cli/agent_test.go +++ b/cli/agent_test.go @@ -279,7 +279,7 @@ func TestWorkspaceAgent(t *testing.T) { } coderAPI.RootHandler.ServeHTTP(w, r) })) - r := dbfake.WorkspaceBuild(t, coderAPI.Database, database.Workspace{ + r := dbfake.WorkspaceBuild(t, coderAPI.Database, database.WorkspaceTable{ OrganizationID: memberUser.OrganizationIDs[0], OwnerID: memberUser.ID, }).WithAgent().Do() From c8de1588f2b39bbbe4177d98b9511e8293ab4518 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Tue, 22 Oct 2024 09:11:26 -0500 Subject: [PATCH 23/23] static time --- coderd/database/modelqueries_internal_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/coderd/database/modelqueries_internal_test.go b/coderd/database/modelqueries_internal_test.go index d679156ef8442..992eb269ddc14 100644 --- a/coderd/database/modelqueries_internal_test.go +++ b/coderd/database/modelqueries_internal_test.go @@ -2,6 +2,7 @@ package database import ( "testing" + "time" "github.com/stretchr/testify/require" @@ -29,6 +30,9 @@ func TestWorkspaceTableConvert(t *testing.T) { Uint: func() uint64 { return 126 }, Float: func() float64 { return 3.14 }, Complex: func() complex128 { return 6.24 }, + Time: func() time.Time { + return time.Date(2020, 5, 2, 5, 19, 21, 30, time.UTC) + }, } // This feels a bit janky, but it works.