mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat(coderd): add has_external_agent flag to template_versions and workspace_builds (#19285)
This pull request introduces support for external workspace management, allowing users to register and manage workspaces that are provisioned and managed outside of the Coder. * Added has_external_agent field to workspace builds and template versions
This commit is contained in:
@@ -4733,28 +4733,6 @@ func (q *querier) UpdateTemplateScheduleByID(ctx context.Context, arg database.U
|
||||
return update(q.log, q.auth, fetch, q.db.UpdateTemplateScheduleByID)(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateTemplateVersionAITaskByJobID(ctx context.Context, arg database.UpdateTemplateVersionAITaskByJobIDParams) error {
|
||||
// An actor is allowed to update the template version AI task flag if they are authorized to update the template.
|
||||
tv, err := q.db.GetTemplateVersionByJobID(ctx, arg.JobID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var obj rbac.Objecter
|
||||
if !tv.TemplateID.Valid {
|
||||
obj = rbac.ResourceTemplate.InOrg(tv.OrganizationID)
|
||||
} else {
|
||||
tpl, err := q.db.GetTemplateByID(ctx, tv.TemplateID.UUID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
obj = tpl
|
||||
}
|
||||
if err := q.authorizeContext(ctx, policy.ActionUpdate, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return q.db.UpdateTemplateVersionAITaskByJobID(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateTemplateVersionByID(ctx context.Context, arg database.UpdateTemplateVersionByIDParams) error {
|
||||
// An actor is allowed to update the template version if they are authorized to update the template.
|
||||
tv, err := q.db.GetTemplateVersionByID(ctx, arg.ID)
|
||||
@@ -4821,6 +4799,28 @@ func (q *querier) UpdateTemplateVersionExternalAuthProvidersByJobID(ctx context.
|
||||
return q.db.UpdateTemplateVersionExternalAuthProvidersByJobID(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateTemplateVersionFlagsByJobID(ctx context.Context, arg database.UpdateTemplateVersionFlagsByJobIDParams) error {
|
||||
// An actor is allowed to update the template version ai task and external agent flag if they are authorized to update the template.
|
||||
tv, err := q.db.GetTemplateVersionByJobID(ctx, arg.JobID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var obj rbac.Objecter
|
||||
if !tv.TemplateID.Valid {
|
||||
obj = rbac.ResourceTemplate.InOrg(tv.OrganizationID)
|
||||
} else {
|
||||
tpl, err := q.db.GetTemplateByID(ctx, tv.TemplateID.UUID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
obj = tpl
|
||||
}
|
||||
if err := q.authorizeContext(ctx, policy.ActionUpdate, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return q.db.UpdateTemplateVersionFlagsByJobID(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateTemplateWorkspacesLastUsedAt(ctx context.Context, arg database.UpdateTemplateWorkspacesLastUsedAtParams) error {
|
||||
fetch := func(ctx context.Context, arg database.UpdateTemplateWorkspacesLastUsedAtParams) (database.Template, error) {
|
||||
return q.db.GetTemplateByID(ctx, arg.TemplateID)
|
||||
@@ -5143,24 +5143,6 @@ func (q *querier) UpdateWorkspaceAutostart(ctx context.Context, arg database.Upd
|
||||
return update(q.log, q.auth, fetch, q.db.UpdateWorkspaceAutostart)(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateWorkspaceBuildAITaskByID(ctx context.Context, arg database.UpdateWorkspaceBuildAITaskByIDParams) error {
|
||||
build, err := q.db.GetWorkspaceBuildByID(ctx, arg.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
workspace, err := q.db.GetWorkspaceByID(ctx, build.WorkspaceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = q.authorizeContext(ctx, policy.ActionUpdate, workspace.RBACObject())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return q.db.UpdateWorkspaceBuildAITaskByID(ctx, arg)
|
||||
}
|
||||
|
||||
// UpdateWorkspaceBuildCostByID is used by the provisioning system to update the cost of a workspace build.
|
||||
func (q *querier) UpdateWorkspaceBuildCostByID(ctx context.Context, arg database.UpdateWorkspaceBuildCostByIDParams) error {
|
||||
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceSystem); err != nil {
|
||||
@@ -5187,6 +5169,24 @@ func (q *querier) UpdateWorkspaceBuildDeadlineByID(ctx context.Context, arg data
|
||||
return q.db.UpdateWorkspaceBuildDeadlineByID(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateWorkspaceBuildFlagsByID(ctx context.Context, arg database.UpdateWorkspaceBuildFlagsByIDParams) error {
|
||||
build, err := q.db.GetWorkspaceBuildByID(ctx, arg.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
workspace, err := q.db.GetWorkspaceByID(ctx, build.WorkspaceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = q.authorizeContext(ctx, policy.ActionUpdate, workspace.RBACObject())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return q.db.UpdateWorkspaceBuildFlagsByID(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateWorkspaceBuildProvisionerStateByID(ctx context.Context, arg database.UpdateWorkspaceBuildProvisionerStateByIDParams) error {
|
||||
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceSystem); err != nil {
|
||||
return err
|
||||
|
||||
@@ -1355,13 +1355,13 @@ func (s *MethodTestSuite) TestTemplate() {
|
||||
dbm.EXPECT().UpdateTemplateScheduleByID(gomock.Any(), arg).Return(nil).AnyTimes()
|
||||
check.Args(arg).Asserts(t1, policy.ActionUpdate)
|
||||
}))
|
||||
s.Run("UpdateTemplateVersionAITaskByJobID", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
|
||||
s.Run("UpdateTemplateVersionFlagsByJobID", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
|
||||
t := testutil.Fake(s.T(), faker, database.Template{})
|
||||
tv := testutil.Fake(s.T(), faker, database.TemplateVersion{TemplateID: uuid.NullUUID{UUID: t.ID, Valid: true}})
|
||||
arg := database.UpdateTemplateVersionAITaskByJobIDParams{JobID: tv.JobID, HasAITask: sql.NullBool{Bool: true, Valid: true}}
|
||||
arg := database.UpdateTemplateVersionFlagsByJobIDParams{JobID: tv.JobID, HasAITask: sql.NullBool{Bool: true, Valid: true}, HasExternalAgent: sql.NullBool{Bool: true, Valid: true}}
|
||||
dbm.EXPECT().GetTemplateVersionByJobID(gomock.Any(), tv.JobID).Return(tv, nil).AnyTimes()
|
||||
dbm.EXPECT().GetTemplateByID(gomock.Any(), t.ID).Return(t, nil).AnyTimes()
|
||||
dbm.EXPECT().UpdateTemplateVersionAITaskByJobID(gomock.Any(), arg).Return(nil).AnyTimes()
|
||||
dbm.EXPECT().UpdateTemplateVersionFlagsByJobID(gomock.Any(), arg).Return(nil).AnyTimes()
|
||||
check.Args(arg).Asserts(t, policy.ActionUpdate)
|
||||
}))
|
||||
s.Run("UpdateTemplateWorkspacesLastUsedAt", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
|
||||
@@ -2955,38 +2955,44 @@ func (s *MethodTestSuite) TestWorkspace() {
|
||||
Deadline: b.Deadline,
|
||||
}).Asserts(w, policy.ActionUpdate)
|
||||
}))
|
||||
s.Run("UpdateWorkspaceBuildAITaskByID", s.Subtest(func(db database.Store, check *expects) {
|
||||
u := dbgen.User(s.T(), db, database.User{})
|
||||
o := dbgen.Organization(s.T(), db, database.Organization{})
|
||||
tpl := dbgen.Template(s.T(), db, database.Template{
|
||||
s.Run("UpdateWorkspaceBuildFlagsByID", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
|
||||
u := testutil.Fake(s.T(), faker, database.User{})
|
||||
o := testutil.Fake(s.T(), faker, database.Organization{})
|
||||
tpl := testutil.Fake(s.T(), faker, database.Template{
|
||||
OrganizationID: o.ID,
|
||||
CreatedBy: u.ID,
|
||||
})
|
||||
tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{
|
||||
tv := testutil.Fake(s.T(), faker, database.TemplateVersion{
|
||||
TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true},
|
||||
OrganizationID: o.ID,
|
||||
CreatedBy: u.ID,
|
||||
})
|
||||
w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{
|
||||
w := testutil.Fake(s.T(), faker, database.Workspace{
|
||||
TemplateID: tpl.ID,
|
||||
OrganizationID: o.ID,
|
||||
OwnerID: u.ID,
|
||||
})
|
||||
j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{
|
||||
j := testutil.Fake(s.T(), faker, database.ProvisionerJob{
|
||||
Type: database.ProvisionerJobTypeWorkspaceBuild,
|
||||
})
|
||||
b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{
|
||||
b := testutil.Fake(s.T(), faker, database.WorkspaceBuild{
|
||||
JobID: j.ID,
|
||||
WorkspaceID: w.ID,
|
||||
TemplateVersionID: tv.ID,
|
||||
})
|
||||
res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: b.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(database.UpdateWorkspaceBuildAITaskByIDParams{
|
||||
HasAITask: sql.NullBool{Bool: true, Valid: true},
|
||||
SidebarAppID: uuid.NullUUID{UUID: app.ID, Valid: true},
|
||||
ID: b.ID,
|
||||
res := testutil.Fake(s.T(), faker, database.WorkspaceResource{JobID: b.JobID})
|
||||
agt := testutil.Fake(s.T(), faker, database.WorkspaceAgent{ResourceID: res.ID})
|
||||
app := testutil.Fake(s.T(), faker, database.WorkspaceApp{AgentID: agt.ID})
|
||||
|
||||
dbm.EXPECT().GetWorkspaceByID(gomock.Any(), w.ID).Return(w, nil).AnyTimes()
|
||||
dbm.EXPECT().GetWorkspaceBuildByID(gomock.Any(), b.ID).Return(b, nil).AnyTimes()
|
||||
dbm.EXPECT().UpdateWorkspaceBuildFlagsByID(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
check.Args(database.UpdateWorkspaceBuildFlagsByIDParams{
|
||||
ID: b.ID,
|
||||
HasAITask: sql.NullBool{Bool: true, Valid: true},
|
||||
HasExternalAgent: sql.NullBool{Bool: true, Valid: true},
|
||||
SidebarAppID: uuid.NullUUID{UUID: app.ID, Valid: true},
|
||||
UpdatedAt: b.UpdatedAt,
|
||||
}).Asserts(w, policy.ActionUpdate)
|
||||
}))
|
||||
s.Run("SoftDeleteWorkspaceByID", s.Subtest(func(db database.Store, check *expects) {
|
||||
|
||||
Reference in New Issue
Block a user