chore: join owner, template, and org in new workspace view (#15116)

Joins in fields like `username`, `avatar_url`, `organization_name`,
`template_name` to `workspaces` via a **view**. 
The view must be maintained moving forward, but this prevents needing to
add RBAC permissions to fetch related workspace fields.
This commit is contained in:
Steven Masley
2024-10-22 09:20:54 -05:00
committed by GitHub
parent 5076161078
commit 343f8ec9ab
81 changed files with 1063 additions and 735 deletions
+6 -6
View File
@@ -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()
@@ -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()
+3 -3
View File
@@ -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()
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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()
+2 -2
View File
@@ -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()
+2 -2
View File
@@ -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()
+4 -4
View File
@@ -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,
+5 -5
View File
@@ -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()
+2 -2
View File
@@ -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,
}).
+3 -3
View File
@@ -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,
}).
+3 -3
View File
@@ -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()
+1 -1
View File
@@ -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()
+3 -3
View File
@@ -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 {
+1 -1
View File
@@ -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),
+9 -20
View File
@@ -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{
+1 -1
View File
@@ -12,7 +12,7 @@ type Auditable interface {
database.Template |
database.TemplateVersion |
database.User |
database.Workspace |
database.WorkspaceTable |
database.GitSSHKey |
database.WorkspaceBuild |
database.AuditableGroup |
+4 -4
View File
@@ -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
+11 -9
View File
@@ -234,22 +234,24 @@ 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(),
Valid: true,
},
})
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 +512,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 +523,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,
+1 -1
View File
@@ -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,
}).
+18 -10
View File
@@ -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)
+77 -80
View File
@@ -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{},
}
@@ -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")
@@ -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,17 @@ 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{
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{})
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,22 +1668,22 @@ 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,
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.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 +1706,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 +1717,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 +1737,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 +1763,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 +1778,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 +1786,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 +1795,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 +1803,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 +1827,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,46 +1842,46 @@ 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})
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.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 +1890,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 +1903,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 +1916,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 +1926,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 +1943,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 +2302,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 +2385,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,
@@ -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{
@@ -2801,7 +2798,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 +2845,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 +2854,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,
})
+3 -3
View File
@@ -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}
}
+1 -1
View File
@@ -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{
+2 -2
View File
@@ -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) {
+102 -60
View File
@@ -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,50 @@ 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.OrganizationName = org.Name
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 +605,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 +1036,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 +5694,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 +5705,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 +5722,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 +6564,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
return database.Workspace{}, err
}
tpl, err := q.getTemplateByIDNoLock(ctx, w.TemplateID)
if err != nil {
return database.GetWorkspaceByAgentIDRow{}, 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 +6591,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 +6610,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 +6836,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 +7801,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 +9450,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 +9467,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 +9477,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 +9742,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 +9766,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 +9778,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 +9861,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 +9870,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 +10905,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 +11201,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:]
}
+6 -6
View File
@@ -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())
+12 -12
View File
@@ -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
}
+5 -5
View File
@@ -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")
+2 -2
View File
@@ -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})
+33
View File
@@ -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,
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,
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
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.';
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);
+14
View File
@@ -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 {
@@ -0,0 +1 @@
DROP VIEW workspaces_expanded;
@@ -0,0 +1,33 @@
CREATE VIEW
workspaces_expanded
AS
SELECT
workspaces.*,
-- Owner
visible_users.avatar_url AS owner_avatar_url,
visible_users.username AS owner_username,
-- Organization
organizations.name AS organization_name,
organizations.display_name AS organization_display_name,
organizations.icon AS organization_icon,
organizations.description AS organization_description,
-- Template
templates.name AS template_name,
templates.display_name AS template_display_name,
templates.icon AS template_icon,
templates.description AS template_description
FROM
workspaces
INNER JOIN
visible_users
ON
workspaces.owner_id = visible_users.id
INNER JOIN
organizations
ON workspaces.organization_id = organizations.id
INNER 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.';
+53 -19
View File
@@ -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 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.
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).
@@ -389,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,
}
}
+9 -1
View File
@@ -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,
@@ -2,8 +2,11 @@ package database
import (
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/coder/coder/v2/testutil"
)
func TestIsAuthorizedQuery(t *testing.T) {
@@ -13,3 +16,41 @@ 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`.
// 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 },
Time: func() time.Time {
return time.Date(2020, 5, 2, 5, 19, 21, 30, time.UTC)
},
}
// 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, staticRandoms)
require.NoError(t, err)
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.")
}
+45 -16
View File
@@ -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"`
}
+6 -6
View File
@@ -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
+4 -4
View File
@@ -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,
+151 -98
View File
@@ -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
@@ -14931,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
@@ -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
@@ -15033,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
@@ -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.
@@ -15066,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
@@ -15085,7 +15122,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 +15156,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 +15242,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 +15348,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 +15420,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 +15434,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 +15498,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 +15611,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 +15694,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,
+18 -15
View File
@@ -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
@@ -238,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
@@ -340,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
@@ -373,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
@@ -403,7 +406,7 @@ CROSS JOIN
SELECT
*
FROM
workspaces
workspaces_expanded as workspaces
WHERE
owner_id = @owner_id
AND deleted = @deleted
+2
View File
@@ -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
+5 -5
View File
@@ -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()
+2 -2
View File
@@ -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{
@@ -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,
+1 -1
View File
@@ -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,
})
+2 -2
View File
@@ -20,13 +20,13 @@ 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{
UserID: user.ID,
})
workspace = dbgen.Workspace(t, db, database.Workspace{
workspace = dbgen.Workspace(t, db, database.WorkspaceTable{
OwnerID: user.ID,
})
)
+1 -1
View File
@@ -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,
})
+3 -3
View File
@@ -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,
})
@@ -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()
@@ -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})
@@ -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)
}
}
@@ -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,
})
@@ -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{
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.Workspace{
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)
@@ -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{
+1 -1
View File
@@ -51,7 +51,7 @@ type CalculateAutostopParams struct {
WorkspaceAutostart string
Now time.Time
Workspace database.Workspace
Workspace database.WorkspaceTable
}
type AutostopTime struct {
+1 -1
View File
@@ -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,
+1 -1
View File
@@ -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,
+3 -3
View File
@@ -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,
-9
View File
@@ -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,
+2 -2
View File
@@ -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,
+11
View File
@@ -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 {
+3 -3
View File
@@ -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 {
+1 -2
View File
@@ -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)
+25 -25
View File
@@ -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 {
+2 -2
View File
@@ -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 {
+7 -71
View File
@@ -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.",
@@ -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,
@@ -189,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.",
@@ -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,
@@ -279,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.",
@@ -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
@@ -685,16 +641,7 @@ type workspaceBuildsData struct {
logSources []database.WorkspaceAgentLogSource
}
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)
}
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)
@@ -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,
+1 -1
View File
@@ -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,
+72 -114
View File
@@ -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,6 +1071,16 @@ func (api *API) putWorkspaceDormant(rw http.ResponseWriter, r *http.Request) {
}
}
// 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.",
Detail: err.Error(),
})
return
}
data, err := api.workspaceData(ctx, []database.Workspace{workspace})
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
@@ -1095,29 +1089,22 @@ func (api *API) putWorkspaceDormant(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 fetching workspace resources.",
Detail: "unable to find workspace owner's username",
})
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
}
@@ -1808,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)
}
@@ -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,
+26 -26
View File
@@ -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,
+1 -1
View File
@@ -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,
@@ -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.
@@ -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,
+1 -1
View File
@@ -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,
+1 -1
View File
@@ -26,9 +26,9 @@ We track the following resources:
| Template<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>active_version_id</td><td>true</td></tr><tr><td>activity_bump</td><td>true</td></tr><tr><td>allow_user_autostart</td><td>true</td></tr><tr><td>allow_user_autostop</td><td>true</td></tr><tr><td>allow_user_cancel_workspace_jobs</td><td>true</td></tr><tr><td>autostart_block_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_weeks</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>default_ttl</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deprecated</td><td>true</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>failure_ttl</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>max_port_sharing_level</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_display_name</td><td>false</td></tr><tr><td>organization_icon</td><td>false</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>organization_name</td><td>false</td></tr><tr><td>provisioner</td><td>true</td></tr><tr><td>require_active_version</td><td>true</td></tr><tr><td>time_til_dormant</td><td>true</td></tr><tr><td>time_til_dormant_autodelete</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_acl</td><td>true</td></tr></tbody></table> |
| TemplateVersion<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>archived</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>external_auth_providers</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>message</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>readme</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
| User<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>avatar_url</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>email</td><td>true</td></tr><tr><td>github_com_user_id</td><td>false</td></tr><tr><td>hashed_one_time_passcode</td><td>false</td></tr><tr><td>hashed_password</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_seen_at</td><td>false</td></tr><tr><td>login_type</td><td>true</td></tr><tr><td>must_reset_password</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>one_time_passcode_expires_at</td><td>true</td></tr><tr><td>quiet_hours_schedule</td><td>true</td></tr><tr><td>rbac_roles</td><td>true</td></tr><tr><td>status</td><td>true</td></tr><tr><td>theme_preference</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>username</td><td>true</td></tr></tbody></table> |
| Workspace<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>automatic_updates</td><td>true</td></tr><tr><td>autostart_schedule</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deleting_at</td><td>true</td></tr><tr><td>dormant_at</td><td>true</td></tr><tr><td>favorite</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>ttl</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
| WorkspaceBuild<br><i>start, stop</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>build_number</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>daily_cost</td><td>false</td></tr><tr><td>deadline</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>initiator_by_avatar_url</td><td>false</td></tr><tr><td>initiator_by_username</td><td>false</td></tr><tr><td>initiator_id</td><td>false</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>max_deadline</td><td>false</td></tr><tr><td>provisioner_state</td><td>false</td></tr><tr><td>reason</td><td>false</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>transition</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>workspace_id</td><td>false</td></tr></tbody></table> |
| WorkspaceProxy<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>derp_enabled</td><td>true</td></tr><tr><td>derp_only</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>region_id</td><td>true</td></tr><tr><td>token_hashed_secret</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>url</td><td>true</td></tr><tr><td>version</td><td>true</td></tr><tr><td>wildcard_hostname</td><td>true</td></tr></tbody></table> |
| WorkspaceTable<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>automatic_updates</td><td>true</td></tr><tr><td>autostart_schedule</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deleting_at</td><td>true</td></tr><tr><td>dormant_at</td><td>true</td></tr><tr><td>favorite</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>ttl</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
<!-- End generated by 'make docs/admin/security/audit-logs.md'. -->
+4 -4
View File
@@ -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,8 +392,8 @@ func Test_diff(t *testing.T) {
},
{
name: "NullSchedules",
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(),
+1 -1
View File
@@ -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.
+1 -1
View File
@@ -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()
+2 -2
View File
@@ -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()
@@ -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()
+2 -2
View File
@@ -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()")
@@ -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 {
+7 -7
View File
@@ -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,
+5 -5
View File
@@ -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,
+1 -1
View File
@@ -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,
+144
View File
@@ -0,0 +1,144 @@
package testutil
import (
"reflect"
"time"
"golang.org/x/xerrors"
)
type Random struct {
String func() string
Bool func() bool
Int func() int64
Uint func() uint64
Float func() float64
Complex func() complex128
Time func() time.Time
}
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 },
Time: func() time.Time { return time.Date(2020, 5, 2, 5, 19, 21, 30, time.UTC) },
}
}
// 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 xerrors.Errorf("s must be a non-nil pointer")
}
v = v.Elem()
if v.Kind() != reflect.Struct {
return xerrors.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 xerrors.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(r.Time()))
return v, nil
default:
// Go to Kind instead
}
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, xerrors.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, xerrors.Errorf("map key : %w", err)
}
kv, err = populateValue(kv, r)
if err != nil {
return v, xerrors.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, xerrors.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, xerrors.Errorf("%s is not supported", v.Kind())
default:
return v, xerrors.Errorf("unsupported kind %s", v.Kind())
}
return v, nil
}