mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat(site): add a provisioner warning to workspace builds (#15686)
This PR adds warnings about provisioner health to workspace build pages. It closes https://github.com/coder/coder/issues/15048  
This commit is contained in:
@@ -1568,6 +1568,10 @@ func (q *querier) GetDeploymentWorkspaceStats(ctx context.Context) (database.Get
|
||||
return q.db.GetDeploymentWorkspaceStats(ctx)
|
||||
}
|
||||
|
||||
func (q *querier) GetEligibleProvisionerDaemonsByProvisionerJobIDs(ctx context.Context, provisionerJobIds []uuid.UUID) ([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow, error) {
|
||||
return fetchWithPostFilter(q.auth, policy.ActionRead, q.db.GetEligibleProvisionerDaemonsByProvisionerJobIDs)(ctx, provisionerJobIds)
|
||||
}
|
||||
|
||||
func (q *querier) GetExternalAuthLink(ctx context.Context, arg database.GetExternalAuthLinkParams) (database.ExternalAuthLink, error) {
|
||||
return fetchWithAction(q.log, q.auth, policy.ActionReadPersonal, q.db.GetExternalAuthLink)(ctx, arg)
|
||||
}
|
||||
|
||||
@@ -2119,6 +2119,29 @@ func (s *MethodTestSuite) TestExtraMethods() {
|
||||
s.NoError(err, "get provisioner daemon by org")
|
||||
check.Args(database.GetProvisionerDaemonsByOrganizationParams{OrganizationID: org.ID}).Asserts(d, policy.ActionRead).Returns(ds)
|
||||
}))
|
||||
s.Run("GetEligibleProvisionerDaemonsByProvisionerJobIDs", s.Subtest(func(db database.Store, check *expects) {
|
||||
org := dbgen.Organization(s.T(), db, database.Organization{})
|
||||
tags := database.StringMap(map[string]string{
|
||||
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
|
||||
})
|
||||
j, err := db.InsertProvisionerJob(context.Background(), database.InsertProvisionerJobParams{
|
||||
OrganizationID: org.ID,
|
||||
Type: database.ProvisionerJobTypeWorkspaceBuild,
|
||||
Tags: tags,
|
||||
Provisioner: database.ProvisionerTypeEcho,
|
||||
StorageMethod: database.ProvisionerStorageMethodFile,
|
||||
})
|
||||
s.NoError(err, "insert provisioner job")
|
||||
d, err := db.UpsertProvisionerDaemon(context.Background(), database.UpsertProvisionerDaemonParams{
|
||||
OrganizationID: org.ID,
|
||||
Tags: tags,
|
||||
Provisioners: []database.ProvisionerType{database.ProvisionerTypeEcho},
|
||||
})
|
||||
s.NoError(err, "insert provisioner daemon")
|
||||
ds, err := db.GetEligibleProvisionerDaemonsByProvisionerJobIDs(context.Background(), []uuid.UUID{j.ID})
|
||||
s.NoError(err, "get provisioner daemon by org")
|
||||
check.Args(uuid.UUIDs{j.ID}).Asserts(d, policy.ActionRead).Returns(ds)
|
||||
}))
|
||||
s.Run("DeleteOldProvisionerDaemons", s.Subtest(func(db database.Store, check *expects) {
|
||||
_, err := db.UpsertProvisionerDaemon(context.Background(), database.UpsertProvisionerDaemonParams{
|
||||
Tags: database.StringMap(map[string]string{
|
||||
|
||||
@@ -503,6 +503,46 @@ func GroupMember(t testing.TB, db database.Store, member database.GroupMemberTab
|
||||
return groupMember
|
||||
}
|
||||
|
||||
// ProvisionerDaemon creates a provisioner daemon as far as the database is concerned. It does not run a provisioner daemon.
|
||||
// If no key is provided, it will create one.
|
||||
func ProvisionerDaemon(t testing.TB, db database.Store, daemon database.ProvisionerDaemon) database.ProvisionerDaemon {
|
||||
t.Helper()
|
||||
|
||||
if daemon.KeyID == uuid.Nil {
|
||||
key, err := db.InsertProvisionerKey(genCtx, database.InsertProvisionerKeyParams{
|
||||
ID: uuid.New(),
|
||||
Name: daemon.Name + "-key",
|
||||
OrganizationID: daemon.OrganizationID,
|
||||
HashedSecret: []byte("secret"),
|
||||
CreatedAt: dbtime.Now(),
|
||||
Tags: daemon.Tags,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
daemon.KeyID = key.ID
|
||||
}
|
||||
|
||||
if daemon.CreatedAt.IsZero() {
|
||||
daemon.CreatedAt = dbtime.Now()
|
||||
}
|
||||
if daemon.Name == "" {
|
||||
daemon.Name = "test-daemon"
|
||||
}
|
||||
|
||||
d, err := db.UpsertProvisionerDaemon(genCtx, database.UpsertProvisionerDaemonParams{
|
||||
Name: daemon.Name,
|
||||
OrganizationID: daemon.OrganizationID,
|
||||
CreatedAt: daemon.CreatedAt,
|
||||
Provisioners: daemon.Provisioners,
|
||||
Tags: daemon.Tags,
|
||||
KeyID: daemon.KeyID,
|
||||
LastSeenAt: daemon.LastSeenAt,
|
||||
Version: daemon.Version,
|
||||
APIVersion: daemon.APIVersion,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return d
|
||||
}
|
||||
|
||||
// ProvisionerJob is a bit more involved to get the values such as "completedAt", "startedAt", "cancelledAt" set. ps
|
||||
// can be set to nil if you are SURE that you don't require a provisionerdaemon to acquire the job in your test.
|
||||
func ProvisionerJob(t testing.TB, db database.Store, ps pubsub.Pubsub, orig database.ProvisionerJob) database.ProvisionerJob {
|
||||
|
||||
@@ -1120,6 +1120,14 @@ func (q *FakeQuerier) getWorkspaceAgentScriptsByAgentIDsNoLock(ids []uuid.UUID)
|
||||
return scripts, nil
|
||||
}
|
||||
|
||||
// getOwnerFromTags returns the lowercase owner from tags, matching SQL's COALESCE(tags ->> 'owner', ”)
|
||||
func getOwnerFromTags(tags map[string]string) string {
|
||||
if owner, ok := tags["owner"]; ok {
|
||||
return strings.ToLower(owner)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (*FakeQuerier) AcquireLock(_ context.Context, _ int64) error {
|
||||
return xerrors.New("AcquireLock must only be called within a transaction")
|
||||
}
|
||||
@@ -2773,6 +2781,63 @@ func (q *FakeQuerier) GetDeploymentWorkspaceStats(ctx context.Context) (database
|
||||
return stat, nil
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) GetEligibleProvisionerDaemonsByProvisionerJobIDs(_ context.Context, provisionerJobIds []uuid.UUID) ([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow, error) {
|
||||
q.mutex.RLock()
|
||||
defer q.mutex.RUnlock()
|
||||
|
||||
results := make([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow, 0)
|
||||
seen := make(map[string]struct{}) // Track unique combinations
|
||||
|
||||
for _, jobID := range provisionerJobIds {
|
||||
var job database.ProvisionerJob
|
||||
found := false
|
||||
for _, j := range q.provisionerJobs {
|
||||
if j.ID == jobID {
|
||||
job = j
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, daemon := range q.provisionerDaemons {
|
||||
if daemon.OrganizationID != job.OrganizationID {
|
||||
continue
|
||||
}
|
||||
|
||||
if !tagsSubset(job.Tags, daemon.Tags) {
|
||||
continue
|
||||
}
|
||||
|
||||
provisionerMatches := false
|
||||
for _, p := range daemon.Provisioners {
|
||||
if p == job.Provisioner {
|
||||
provisionerMatches = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !provisionerMatches {
|
||||
continue
|
||||
}
|
||||
|
||||
key := jobID.String() + "-" + daemon.ID.String()
|
||||
if _, exists := seen[key]; exists {
|
||||
continue
|
||||
}
|
||||
seen[key] = struct{}{}
|
||||
|
||||
results = append(results, database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow{
|
||||
JobID: jobID,
|
||||
ProvisionerDaemon: daemon,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) GetExternalAuthLink(_ context.Context, arg database.GetExternalAuthLinkParams) (database.ExternalAuthLink, error) {
|
||||
if err := validateDatabaseType(arg); err != nil {
|
||||
return database.ExternalAuthLink{}, err
|
||||
@@ -10344,25 +10409,26 @@ func (q *FakeQuerier) UpsertOAuthSigningKey(_ context.Context, value string) err
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) UpsertProvisionerDaemon(_ context.Context, arg database.UpsertProvisionerDaemonParams) (database.ProvisionerDaemon, error) {
|
||||
err := validateDatabaseType(arg)
|
||||
if err != nil {
|
||||
if err := validateDatabaseType(arg); err != nil {
|
||||
return database.ProvisionerDaemon{}, err
|
||||
}
|
||||
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
for _, d := range q.provisionerDaemons {
|
||||
if d.Name == arg.Name {
|
||||
if d.Tags[provisionersdk.TagScope] == provisionersdk.ScopeOrganization && arg.Tags[provisionersdk.TagOwner] != "" {
|
||||
continue
|
||||
}
|
||||
if d.Tags[provisionersdk.TagScope] == provisionersdk.ScopeUser && arg.Tags[provisionersdk.TagOwner] != d.Tags[provisionersdk.TagOwner] {
|
||||
continue
|
||||
}
|
||||
|
||||
// Look for existing daemon using the same composite key as SQL
|
||||
for i, d := range q.provisionerDaemons {
|
||||
if d.OrganizationID == arg.OrganizationID &&
|
||||
d.Name == arg.Name &&
|
||||
getOwnerFromTags(d.Tags) == getOwnerFromTags(arg.Tags) {
|
||||
d.Provisioners = arg.Provisioners
|
||||
d.Tags = maps.Clone(arg.Tags)
|
||||
d.Version = arg.Version
|
||||
d.LastSeenAt = arg.LastSeenAt
|
||||
d.Version = arg.Version
|
||||
d.APIVersion = arg.APIVersion
|
||||
d.OrganizationID = arg.OrganizationID
|
||||
d.KeyID = arg.KeyID
|
||||
q.provisionerDaemons[i] = d
|
||||
return d, nil
|
||||
}
|
||||
}
|
||||
@@ -10372,7 +10438,6 @@ func (q *FakeQuerier) UpsertProvisionerDaemon(_ context.Context, arg database.Up
|
||||
Name: arg.Name,
|
||||
Provisioners: arg.Provisioners,
|
||||
Tags: maps.Clone(arg.Tags),
|
||||
ReplicaID: uuid.NullUUID{},
|
||||
LastSeenAt: arg.LastSeenAt,
|
||||
Version: arg.Version,
|
||||
APIVersion: arg.APIVersion,
|
||||
|
||||
@@ -637,6 +637,13 @@ func (m queryMetricsStore) GetDeploymentWorkspaceStats(ctx context.Context) (dat
|
||||
return row, err
|
||||
}
|
||||
|
||||
func (m queryMetricsStore) GetEligibleProvisionerDaemonsByProvisionerJobIDs(ctx context.Context, provisionerJobIds []uuid.UUID) ([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow, error) {
|
||||
start := time.Now()
|
||||
r0, r1 := m.s.GetEligibleProvisionerDaemonsByProvisionerJobIDs(ctx, provisionerJobIds)
|
||||
m.queryLatencies.WithLabelValues("GetEligibleProvisionerDaemonsByProvisionerJobIDs").Observe(time.Since(start).Seconds())
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (m queryMetricsStore) GetExternalAuthLink(ctx context.Context, arg database.GetExternalAuthLinkParams) (database.ExternalAuthLink, error) {
|
||||
start := time.Now()
|
||||
link, err := m.s.GetExternalAuthLink(ctx, arg)
|
||||
|
||||
@@ -1281,6 +1281,21 @@ func (mr *MockStoreMockRecorder) GetDeploymentWorkspaceStats(arg0 any) *gomock.C
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeploymentWorkspaceStats", reflect.TypeOf((*MockStore)(nil).GetDeploymentWorkspaceStats), arg0)
|
||||
}
|
||||
|
||||
// GetEligibleProvisionerDaemonsByProvisionerJobIDs mocks base method.
|
||||
func (m *MockStore) GetEligibleProvisionerDaemonsByProvisionerJobIDs(arg0 context.Context, arg1 []uuid.UUID) ([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetEligibleProvisionerDaemonsByProvisionerJobIDs", arg0, arg1)
|
||||
ret0, _ := ret[0].([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetEligibleProvisionerDaemonsByProvisionerJobIDs indicates an expected call of GetEligibleProvisionerDaemonsByProvisionerJobIDs.
|
||||
func (mr *MockStoreMockRecorder) GetEligibleProvisionerDaemonsByProvisionerJobIDs(arg0, arg1 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEligibleProvisionerDaemonsByProvisionerJobIDs", reflect.TypeOf((*MockStore)(nil).GetEligibleProvisionerDaemonsByProvisionerJobIDs), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetExternalAuthLink mocks base method.
|
||||
func (m *MockStore) GetExternalAuthLink(arg0 context.Context, arg1 database.GetExternalAuthLinkParams) (database.ExternalAuthLink, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
@@ -269,6 +269,10 @@ func (p ProvisionerDaemon) RBACObject() rbac.Object {
|
||||
InOrg(p.OrganizationID)
|
||||
}
|
||||
|
||||
func (p GetEligibleProvisionerDaemonsByProvisionerJobIDsRow) RBACObject() rbac.Object {
|
||||
return p.ProvisionerDaemon.RBACObject()
|
||||
}
|
||||
|
||||
func (p ProvisionerKey) RBACObject() rbac.Object {
|
||||
return rbac.ResourceProvisionerKeys.
|
||||
WithID(p.ID).
|
||||
|
||||
@@ -145,6 +145,7 @@ type sqlcQuerier interface {
|
||||
GetDeploymentWorkspaceAgentStats(ctx context.Context, createdAt time.Time) (GetDeploymentWorkspaceAgentStatsRow, error)
|
||||
GetDeploymentWorkspaceAgentUsageStats(ctx context.Context, createdAt time.Time) (GetDeploymentWorkspaceAgentUsageStatsRow, error)
|
||||
GetDeploymentWorkspaceStats(ctx context.Context) (GetDeploymentWorkspaceStatsRow, error)
|
||||
GetEligibleProvisionerDaemonsByProvisionerJobIDs(ctx context.Context, provisionerJobIds []uuid.UUID) ([]GetEligibleProvisionerDaemonsByProvisionerJobIDsRow, error)
|
||||
GetExternalAuthLink(ctx context.Context, arg GetExternalAuthLinkParams) (ExternalAuthLink, error)
|
||||
GetExternalAuthLinksByUserID(ctx context.Context, userID uuid.UUID) ([]ExternalAuthLink, error)
|
||||
GetFailedWorkspaceBuildsByTemplateID(ctx context.Context, arg GetFailedWorkspaceBuildsByTemplateIDParams) ([]GetFailedWorkspaceBuildsByTemplateIDRow, error)
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/httpmw"
|
||||
"github.com/coder/coder/v2/coderd/rbac"
|
||||
"github.com/coder/coder/v2/coderd/rbac/policy"
|
||||
"github.com/coder/coder/v2/provisionersdk"
|
||||
"github.com/coder/coder/v2/testutil"
|
||||
)
|
||||
|
||||
@@ -211,6 +212,145 @@ func TestGetDeploymentWorkspaceAgentUsageStats(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetEligibleProvisionerDaemonsByProvisionerJobIDs(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("NoJobsReturnsEmpty", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
db, _ := dbtestutil.NewDB(t)
|
||||
daemons, err := db.GetEligibleProvisionerDaemonsByProvisionerJobIDs(context.Background(), []uuid.UUID{})
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, daemons)
|
||||
})
|
||||
|
||||
t.Run("MatchesProvisionerType", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
db, _ := dbtestutil.NewDB(t)
|
||||
org := dbgen.Organization(t, db, database.Organization{})
|
||||
|
||||
job := dbgen.ProvisionerJob(t, db, nil, database.ProvisionerJob{
|
||||
OrganizationID: org.ID,
|
||||
Type: database.ProvisionerJobTypeWorkspaceBuild,
|
||||
Provisioner: database.ProvisionerTypeEcho,
|
||||
Tags: database.StringMap{
|
||||
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
|
||||
},
|
||||
})
|
||||
|
||||
matchingDaemon := dbgen.ProvisionerDaemon(t, db, database.ProvisionerDaemon{
|
||||
Name: "matching-daemon",
|
||||
OrganizationID: org.ID,
|
||||
Provisioners: []database.ProvisionerType{database.ProvisionerTypeEcho},
|
||||
Tags: database.StringMap{
|
||||
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
|
||||
},
|
||||
})
|
||||
|
||||
dbgen.ProvisionerDaemon(t, db, database.ProvisionerDaemon{
|
||||
Name: "non-matching-daemon",
|
||||
OrganizationID: org.ID,
|
||||
Provisioners: []database.ProvisionerType{database.ProvisionerTypeTerraform},
|
||||
Tags: database.StringMap{
|
||||
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
|
||||
},
|
||||
})
|
||||
|
||||
daemons, err := db.GetEligibleProvisionerDaemonsByProvisionerJobIDs(context.Background(), []uuid.UUID{job.ID})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, daemons, 1)
|
||||
require.Equal(t, matchingDaemon.ID, daemons[0].ProvisionerDaemon.ID)
|
||||
})
|
||||
|
||||
t.Run("MatchesOrganizationScope", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
db, _ := dbtestutil.NewDB(t)
|
||||
org := dbgen.Organization(t, db, database.Organization{})
|
||||
|
||||
job := dbgen.ProvisionerJob(t, db, nil, database.ProvisionerJob{
|
||||
OrganizationID: org.ID,
|
||||
Type: database.ProvisionerJobTypeWorkspaceBuild,
|
||||
Provisioner: database.ProvisionerTypeEcho,
|
||||
Tags: database.StringMap{
|
||||
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
|
||||
provisionersdk.TagOwner: "",
|
||||
},
|
||||
})
|
||||
|
||||
orgDaemon := dbgen.ProvisionerDaemon(t, db, database.ProvisionerDaemon{
|
||||
Name: "org-daemon",
|
||||
OrganizationID: org.ID,
|
||||
Provisioners: []database.ProvisionerType{database.ProvisionerTypeEcho},
|
||||
Tags: database.StringMap{
|
||||
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
|
||||
provisionersdk.TagOwner: "",
|
||||
},
|
||||
})
|
||||
|
||||
dbgen.ProvisionerDaemon(t, db, database.ProvisionerDaemon{
|
||||
Name: "user-daemon",
|
||||
OrganizationID: org.ID,
|
||||
Provisioners: []database.ProvisionerType{database.ProvisionerTypeEcho},
|
||||
Tags: database.StringMap{
|
||||
provisionersdk.TagScope: provisionersdk.ScopeUser,
|
||||
},
|
||||
})
|
||||
|
||||
daemons, err := db.GetEligibleProvisionerDaemonsByProvisionerJobIDs(context.Background(), []uuid.UUID{job.ID})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, daemons, 1)
|
||||
require.Equal(t, orgDaemon.ID, daemons[0].ProvisionerDaemon.ID)
|
||||
})
|
||||
|
||||
t.Run("MatchesMultipleProvisioners", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
db, _ := dbtestutil.NewDB(t)
|
||||
org := dbgen.Organization(t, db, database.Organization{})
|
||||
|
||||
job := dbgen.ProvisionerJob(t, db, nil, database.ProvisionerJob{
|
||||
OrganizationID: org.ID,
|
||||
Type: database.ProvisionerJobTypeWorkspaceBuild,
|
||||
Provisioner: database.ProvisionerTypeEcho,
|
||||
Tags: database.StringMap{
|
||||
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
|
||||
},
|
||||
})
|
||||
|
||||
daemon1 := dbgen.ProvisionerDaemon(t, db, database.ProvisionerDaemon{
|
||||
Name: "daemon-1",
|
||||
OrganizationID: org.ID,
|
||||
Provisioners: []database.ProvisionerType{database.ProvisionerTypeEcho},
|
||||
Tags: database.StringMap{
|
||||
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
|
||||
},
|
||||
})
|
||||
|
||||
daemon2 := dbgen.ProvisionerDaemon(t, db, database.ProvisionerDaemon{
|
||||
Name: "daemon-2",
|
||||
OrganizationID: org.ID,
|
||||
Provisioners: []database.ProvisionerType{database.ProvisionerTypeEcho},
|
||||
Tags: database.StringMap{
|
||||
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
|
||||
},
|
||||
})
|
||||
|
||||
dbgen.ProvisionerDaemon(t, db, database.ProvisionerDaemon{
|
||||
Name: "daemon-3",
|
||||
OrganizationID: org.ID,
|
||||
Provisioners: []database.ProvisionerType{database.ProvisionerTypeTerraform},
|
||||
Tags: database.StringMap{
|
||||
provisionersdk.TagScope: provisionersdk.ScopeOrganization,
|
||||
},
|
||||
})
|
||||
|
||||
daemons, err := db.GetEligibleProvisionerDaemonsByProvisionerJobIDs(context.Background(), []uuid.UUID{job.ID})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, daemons, 2)
|
||||
|
||||
daemonIDs := []uuid.UUID{daemons[0].ProvisionerDaemon.ID, daemons[1].ProvisionerDaemon.ID}
|
||||
require.ElementsMatch(t, []uuid.UUID{daemon1.ID, daemon2.ID}, daemonIDs)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetWorkspaceAgentUsageStats(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -5255,6 +5255,60 @@ func (q *sqlQuerier) DeleteOldProvisionerDaemons(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
const getEligibleProvisionerDaemonsByProvisionerJobIDs = `-- name: GetEligibleProvisionerDaemonsByProvisionerJobIDs :many
|
||||
SELECT DISTINCT
|
||||
provisioner_jobs.id as job_id, provisioner_daemons.id, provisioner_daemons.created_at, provisioner_daemons.name, provisioner_daemons.provisioners, provisioner_daemons.replica_id, provisioner_daemons.tags, provisioner_daemons.last_seen_at, provisioner_daemons.version, provisioner_daemons.api_version, provisioner_daemons.organization_id, provisioner_daemons.key_id
|
||||
FROM
|
||||
provisioner_jobs
|
||||
JOIN
|
||||
provisioner_daemons ON provisioner_daemons.organization_id = provisioner_jobs.organization_id
|
||||
AND provisioner_tagset_contains(provisioner_daemons.tags::tagset, provisioner_jobs.tags::tagset)
|
||||
AND provisioner_jobs.provisioner = ANY(provisioner_daemons.provisioners)
|
||||
WHERE
|
||||
provisioner_jobs.id = ANY($1 :: uuid[])
|
||||
`
|
||||
|
||||
type GetEligibleProvisionerDaemonsByProvisionerJobIDsRow struct {
|
||||
JobID uuid.UUID `db:"job_id" json:"job_id"`
|
||||
ProvisionerDaemon ProvisionerDaemon `db:"provisioner_daemon" json:"provisioner_daemon"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) GetEligibleProvisionerDaemonsByProvisionerJobIDs(ctx context.Context, provisionerJobIds []uuid.UUID) ([]GetEligibleProvisionerDaemonsByProvisionerJobIDsRow, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getEligibleProvisionerDaemonsByProvisionerJobIDs, pq.Array(provisionerJobIds))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetEligibleProvisionerDaemonsByProvisionerJobIDsRow
|
||||
for rows.Next() {
|
||||
var i GetEligibleProvisionerDaemonsByProvisionerJobIDsRow
|
||||
if err := rows.Scan(
|
||||
&i.JobID,
|
||||
&i.ProvisionerDaemon.ID,
|
||||
&i.ProvisionerDaemon.CreatedAt,
|
||||
&i.ProvisionerDaemon.Name,
|
||||
pq.Array(&i.ProvisionerDaemon.Provisioners),
|
||||
&i.ProvisionerDaemon.ReplicaID,
|
||||
&i.ProvisionerDaemon.Tags,
|
||||
&i.ProvisionerDaemon.LastSeenAt,
|
||||
&i.ProvisionerDaemon.Version,
|
||||
&i.ProvisionerDaemon.APIVersion,
|
||||
&i.ProvisionerDaemon.OrganizationID,
|
||||
&i.ProvisionerDaemon.KeyID,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getProvisionerDaemons = `-- name: GetProvisionerDaemons :many
|
||||
SELECT
|
||||
id, created_at, name, provisioners, replica_id, tags, last_seen_at, version, api_version, organization_id, key_id
|
||||
|
||||
@@ -16,6 +16,18 @@ WHERE
|
||||
-- adding support for searching by tags:
|
||||
(@want_tags :: tagset = 'null' :: tagset OR provisioner_tagset_contains(provisioner_daemons.tags::tagset, @want_tags::tagset));
|
||||
|
||||
-- name: GetEligibleProvisionerDaemonsByProvisionerJobIDs :many
|
||||
SELECT DISTINCT
|
||||
provisioner_jobs.id as job_id, sqlc.embed(provisioner_daemons)
|
||||
FROM
|
||||
provisioner_jobs
|
||||
JOIN
|
||||
provisioner_daemons ON provisioner_daemons.organization_id = provisioner_jobs.organization_id
|
||||
AND provisioner_tagset_contains(provisioner_daemons.tags::tagset, provisioner_jobs.tags::tagset)
|
||||
AND provisioner_jobs.provisioner = ANY(provisioner_daemons.provisioners)
|
||||
WHERE
|
||||
provisioner_jobs.id = ANY(@provisioner_job_ids :: uuid[]);
|
||||
|
||||
-- name: DeleteOldProvisionerDaemons :exec
|
||||
-- Delete provisioner daemons that have been created at least a week ago
|
||||
-- and have not connected to coderd since a week.
|
||||
|
||||
+52
-31
@@ -202,6 +202,7 @@ func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) {
|
||||
data.scripts,
|
||||
data.logSources,
|
||||
data.templateVersions,
|
||||
data.provisionerDaemons,
|
||||
)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
@@ -291,7 +292,7 @@ func (api *API) workspaceBuildByBuildNumber(rw http.ResponseWriter, r *http.Requ
|
||||
data.scripts,
|
||||
data.logSources,
|
||||
data.templateVersions[0],
|
||||
nil,
|
||||
data.provisionerDaemons,
|
||||
)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
@@ -395,10 +396,6 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
var matchedProvisioners codersdk.MatchedProvisioners
|
||||
if provisionerJob != nil {
|
||||
matchedProvisioners = db2sdk.MatchedProvisioners(provisionerDaemons, provisionerJob.CreatedAt, provisionerdserver.StaleInterval)
|
||||
}
|
||||
apiBuild, err := api.convertWorkspaceBuild(
|
||||
*workspaceBuild,
|
||||
workspace,
|
||||
@@ -413,7 +410,7 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
|
||||
[]database.WorkspaceAgentScript{},
|
||||
[]database.WorkspaceAgentLogSource{},
|
||||
database.TemplateVersion{},
|
||||
&matchedProvisioners,
|
||||
provisionerDaemons,
|
||||
)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
@@ -648,14 +645,15 @@ func (api *API) workspaceBuildTimings(rw http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
type workspaceBuildsData struct {
|
||||
jobs []database.GetProvisionerJobsByIDsWithQueuePositionRow
|
||||
templateVersions []database.TemplateVersion
|
||||
resources []database.WorkspaceResource
|
||||
metadata []database.WorkspaceResourceMetadatum
|
||||
agents []database.WorkspaceAgent
|
||||
apps []database.WorkspaceApp
|
||||
scripts []database.WorkspaceAgentScript
|
||||
logSources []database.WorkspaceAgentLogSource
|
||||
jobs []database.GetProvisionerJobsByIDsWithQueuePositionRow
|
||||
templateVersions []database.TemplateVersion
|
||||
resources []database.WorkspaceResource
|
||||
metadata []database.WorkspaceResourceMetadatum
|
||||
agents []database.WorkspaceAgent
|
||||
apps []database.WorkspaceApp
|
||||
scripts []database.WorkspaceAgentScript
|
||||
logSources []database.WorkspaceAgentLogSource
|
||||
provisionerDaemons []database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow
|
||||
}
|
||||
|
||||
func (api *API) workspaceBuildsData(ctx context.Context, workspaceBuilds []database.WorkspaceBuild) (workspaceBuildsData, error) {
|
||||
@@ -667,6 +665,17 @@ func (api *API) workspaceBuildsData(ctx context.Context, workspaceBuilds []datab
|
||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return workspaceBuildsData{}, xerrors.Errorf("get provisioner jobs: %w", err)
|
||||
}
|
||||
pendingJobIDs := []uuid.UUID{}
|
||||
for _, job := range jobs {
|
||||
if job.ProvisionerJob.JobStatus == database.ProvisionerJobStatusPending {
|
||||
pendingJobIDs = append(pendingJobIDs, job.ProvisionerJob.ID)
|
||||
}
|
||||
}
|
||||
|
||||
pendingJobProvisioners, err := api.Database.GetEligibleProvisionerDaemonsByProvisionerJobIDs(ctx, pendingJobIDs)
|
||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return workspaceBuildsData{}, xerrors.Errorf("get provisioner daemons: %w", err)
|
||||
}
|
||||
|
||||
templateVersionIDs := make([]uuid.UUID, 0, len(workspaceBuilds))
|
||||
for _, build := range workspaceBuilds {
|
||||
@@ -687,8 +696,9 @@ func (api *API) workspaceBuildsData(ctx context.Context, workspaceBuilds []datab
|
||||
|
||||
if len(resources) == 0 {
|
||||
return workspaceBuildsData{
|
||||
jobs: jobs,
|
||||
templateVersions: templateVersions,
|
||||
jobs: jobs,
|
||||
templateVersions: templateVersions,
|
||||
provisionerDaemons: pendingJobProvisioners,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -711,10 +721,11 @@ func (api *API) workspaceBuildsData(ctx context.Context, workspaceBuilds []datab
|
||||
|
||||
if len(resources) == 0 {
|
||||
return workspaceBuildsData{
|
||||
jobs: jobs,
|
||||
templateVersions: templateVersions,
|
||||
resources: resources,
|
||||
metadata: metadata,
|
||||
jobs: jobs,
|
||||
templateVersions: templateVersions,
|
||||
resources: resources,
|
||||
metadata: metadata,
|
||||
provisionerDaemons: pendingJobProvisioners,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -751,14 +762,15 @@ func (api *API) workspaceBuildsData(ctx context.Context, workspaceBuilds []datab
|
||||
}
|
||||
|
||||
return workspaceBuildsData{
|
||||
jobs: jobs,
|
||||
templateVersions: templateVersions,
|
||||
resources: resources,
|
||||
metadata: metadata,
|
||||
agents: agents,
|
||||
apps: apps,
|
||||
scripts: scripts,
|
||||
logSources: logSources,
|
||||
jobs: jobs,
|
||||
templateVersions: templateVersions,
|
||||
resources: resources,
|
||||
metadata: metadata,
|
||||
agents: agents,
|
||||
apps: apps,
|
||||
scripts: scripts,
|
||||
logSources: logSources,
|
||||
provisionerDaemons: pendingJobProvisioners,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -773,6 +785,7 @@ func (api *API) convertWorkspaceBuilds(
|
||||
agentScripts []database.WorkspaceAgentScript,
|
||||
agentLogSources []database.WorkspaceAgentLogSource,
|
||||
templateVersions []database.TemplateVersion,
|
||||
provisionerDaemons []database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow,
|
||||
) ([]codersdk.WorkspaceBuild, error) {
|
||||
workspaceByID := map[uuid.UUID]database.Workspace{}
|
||||
for _, workspace := range workspaces {
|
||||
@@ -814,7 +827,7 @@ func (api *API) convertWorkspaceBuilds(
|
||||
agentScripts,
|
||||
agentLogSources,
|
||||
templateVersion,
|
||||
nil,
|
||||
provisionerDaemons,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("converting workspace build: %w", err)
|
||||
@@ -837,7 +850,7 @@ func (api *API) convertWorkspaceBuild(
|
||||
agentScripts []database.WorkspaceAgentScript,
|
||||
agentLogSources []database.WorkspaceAgentLogSource,
|
||||
templateVersion database.TemplateVersion,
|
||||
matchedProvisioners *codersdk.MatchedProvisioners,
|
||||
provisionerDaemons []database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow,
|
||||
) (codersdk.WorkspaceBuild, error) {
|
||||
resourcesByJobID := map[uuid.UUID][]database.WorkspaceResource{}
|
||||
for _, resource := range workspaceResources {
|
||||
@@ -863,6 +876,14 @@ func (api *API) convertWorkspaceBuild(
|
||||
for _, logSource := range agentLogSources {
|
||||
logSourcesByAgentID[logSource.WorkspaceAgentID] = append(logSourcesByAgentID[logSource.WorkspaceAgentID], logSource)
|
||||
}
|
||||
provisionerDaemonsForThisWorkspaceBuild := []database.ProvisionerDaemon{}
|
||||
for _, provisionerDaemon := range provisionerDaemons {
|
||||
if provisionerDaemon.JobID != job.ProvisionerJob.ID {
|
||||
continue
|
||||
}
|
||||
provisionerDaemonsForThisWorkspaceBuild = append(provisionerDaemonsForThisWorkspaceBuild, provisionerDaemon.ProvisionerDaemon)
|
||||
}
|
||||
matchedProvisioners := db2sdk.MatchedProvisioners(provisionerDaemonsForThisWorkspaceBuild, job.ProvisionerJob.CreatedAt, provisionerdserver.StaleInterval)
|
||||
|
||||
resources := resourcesByJobID[job.ProvisionerJob.ID]
|
||||
apiResources := make([]codersdk.WorkspaceResource, 0)
|
||||
@@ -930,7 +951,7 @@ func (api *API) convertWorkspaceBuild(
|
||||
Resources: apiResources,
|
||||
Status: codersdk.ConvertWorkspaceStatus(apiJob.Status, transition),
|
||||
DailyCost: build.DailyCost,
|
||||
MatchedProvisioners: matchedProvisioners,
|
||||
MatchedProvisioners: &matchedProvisioners,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/httpapi"
|
||||
"github.com/coder/coder/v2/coderd/httpmw"
|
||||
"github.com/coder/coder/v2/coderd/notifications"
|
||||
"github.com/coder/coder/v2/coderd/provisionerdserver"
|
||||
"github.com/coder/coder/v2/coderd/rbac"
|
||||
"github.com/coder/coder/v2/coderd/rbac/policy"
|
||||
"github.com/coder/coder/v2/coderd/schedule"
|
||||
@@ -612,10 +611,9 @@ func createWorkspace(
|
||||
}
|
||||
|
||||
var (
|
||||
provisionerJob *database.ProvisionerJob
|
||||
workspaceBuild *database.WorkspaceBuild
|
||||
provisionerDaemons []database.ProvisionerDaemon
|
||||
matchedProvisioners codersdk.MatchedProvisioners
|
||||
provisionerJob *database.ProvisionerJob
|
||||
workspaceBuild *database.WorkspaceBuild
|
||||
provisionerDaemons []database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow
|
||||
)
|
||||
err = api.Database.InTx(func(db database.Store) error {
|
||||
now := dbtime.Now()
|
||||
@@ -688,9 +686,6 @@ 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))
|
||||
}
|
||||
if provisionerJob != nil {
|
||||
matchedProvisioners = db2sdk.MatchedProvisioners(provisionerDaemons, provisionerJob.CreatedAt, provisionerdserver.StaleInterval)
|
||||
}
|
||||
|
||||
auditReq.New = workspace.WorkspaceTable()
|
||||
|
||||
@@ -713,7 +708,7 @@ func createWorkspace(
|
||||
[]database.WorkspaceAgentScript{},
|
||||
[]database.WorkspaceAgentLogSource{},
|
||||
database.TemplateVersion{},
|
||||
&matchedProvisioners,
|
||||
provisionerDaemons,
|
||||
)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
@@ -1843,6 +1838,7 @@ func (api *API) workspaceData(ctx context.Context, workspaces []database.Workspa
|
||||
data.scripts,
|
||||
data.logSources,
|
||||
data.templateVersions,
|
||||
data.provisionerDaemons,
|
||||
)
|
||||
if err != nil {
|
||||
return workspaceData{}, xerrors.Errorf("convert workspace builds: %w", err)
|
||||
|
||||
@@ -214,7 +214,7 @@ func (b *Builder) Build(
|
||||
authFunc func(action policy.Action, object rbac.Objecter) bool,
|
||||
auditBaggage audit.WorkspaceBuildBaggage,
|
||||
) (
|
||||
*database.WorkspaceBuild, *database.ProvisionerJob, []database.ProvisionerDaemon, error,
|
||||
*database.WorkspaceBuild, *database.ProvisionerJob, []database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow, error,
|
||||
) {
|
||||
var err error
|
||||
b.ctx, err = audit.BaggageToContext(ctx, auditBaggage)
|
||||
@@ -228,7 +228,7 @@ func (b *Builder) Build(
|
||||
// later reads are consistent with earlier ones.
|
||||
var workspaceBuild *database.WorkspaceBuild
|
||||
var provisionerJob *database.ProvisionerJob
|
||||
var provisionerDaemons []database.ProvisionerDaemon
|
||||
var provisionerDaemons []database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow
|
||||
err = database.ReadModifyUpdate(store, func(tx database.Store) error {
|
||||
var err error
|
||||
b.store = tx
|
||||
@@ -248,7 +248,7 @@ func (b *Builder) Build(
|
||||
//
|
||||
// In order to utilize this cache, the functions that compute build attributes use a pointer receiver type.
|
||||
func (b *Builder) buildTx(authFunc func(action policy.Action, object rbac.Objecter) bool) (
|
||||
*database.WorkspaceBuild, *database.ProvisionerJob, []database.ProvisionerDaemon, error,
|
||||
*database.WorkspaceBuild, *database.ProvisionerJob, []database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow, error,
|
||||
) {
|
||||
if authFunc != nil {
|
||||
err := b.authorize(authFunc)
|
||||
@@ -338,15 +338,12 @@ func (b *Builder) buildTx(authFunc func(action policy.Action, object rbac.Object
|
||||
// to read all provisioner daemons. We need to retrieve the eligible
|
||||
// provisioner daemons for this job to show in the UI if there is no
|
||||
// matching provisioner daemon.
|
||||
provisionerDaemons, err := b.store.GetProvisionerDaemonsByOrganization(dbauthz.AsSystemReadProvisionerDaemons(b.ctx), database.GetProvisionerDaemonsByOrganizationParams{
|
||||
OrganizationID: template.OrganizationID,
|
||||
WantTags: provisionerJob.Tags,
|
||||
})
|
||||
provisionerDaemons, err := b.store.GetEligibleProvisionerDaemonsByProvisionerJobIDs(dbauthz.AsSystemReadProvisionerDaemons(b.ctx), []uuid.UUID{provisionerJob.ID})
|
||||
if err != nil {
|
||||
// NOTE: we do **not** want to fail a workspace build if we fail to
|
||||
// retrieve provisioner daemons. This is just to show in the UI if there
|
||||
// is no matching provisioner daemon for the job.
|
||||
provisionerDaemons = []database.ProvisionerDaemon{}
|
||||
provisionerDaemons = []database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow{}
|
||||
}
|
||||
|
||||
templateVersionID, err := b.getTemplateVersionID()
|
||||
|
||||
@@ -61,7 +61,7 @@ func TestBuilder_NoOptions(t *testing.T) {
|
||||
withRichParameters(nil),
|
||||
withParameterSchemas(inactiveJobID, nil),
|
||||
withWorkspaceTags(inactiveVersionID, nil),
|
||||
withProvisionerDaemons([]database.ProvisionerDaemon{}),
|
||||
withProvisionerDaemons([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow{}),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {
|
||||
@@ -116,7 +116,7 @@ func TestBuilder_Initiator(t *testing.T) {
|
||||
withRichParameters(nil),
|
||||
withParameterSchemas(inactiveJobID, nil),
|
||||
withWorkspaceTags(inactiveVersionID, nil),
|
||||
withProvisionerDaemons([]database.ProvisionerDaemon{}),
|
||||
withProvisionerDaemons([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow{}),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {
|
||||
@@ -161,7 +161,7 @@ func TestBuilder_Baggage(t *testing.T) {
|
||||
withRichParameters(nil),
|
||||
withParameterSchemas(inactiveJobID, nil),
|
||||
withWorkspaceTags(inactiveVersionID, nil),
|
||||
withProvisionerDaemons([]database.ProvisionerDaemon{}),
|
||||
withProvisionerDaemons([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow{}),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {
|
||||
@@ -198,7 +198,7 @@ func TestBuilder_Reason(t *testing.T) {
|
||||
withRichParameters(nil),
|
||||
withParameterSchemas(inactiveJobID, nil),
|
||||
withWorkspaceTags(inactiveVersionID, nil),
|
||||
withProvisionerDaemons([]database.ProvisionerDaemon{}),
|
||||
withProvisionerDaemons([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow{}),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(_ database.InsertProvisionerJobParams) {
|
||||
@@ -234,7 +234,7 @@ func TestBuilder_ActiveVersion(t *testing.T) {
|
||||
withLastBuildNotFound,
|
||||
withParameterSchemas(activeJobID, nil),
|
||||
withWorkspaceTags(activeVersionID, nil),
|
||||
withProvisionerDaemons([]database.ProvisionerDaemon{}),
|
||||
withProvisionerDaemons([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow{}),
|
||||
// previous rich parameters are not queried because there is no previous build.
|
||||
|
||||
// Outputs
|
||||
@@ -324,7 +324,7 @@ func TestWorkspaceBuildWithTags(t *testing.T) {
|
||||
withRichParameters(nil),
|
||||
withParameterSchemas(inactiveJobID, nil),
|
||||
withWorkspaceTags(inactiveVersionID, workspaceTags),
|
||||
withProvisionerDaemons([]database.ProvisionerDaemon{}),
|
||||
withProvisionerDaemons([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow{}),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {
|
||||
@@ -416,7 +416,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) {
|
||||
withRichParameters(initialBuildParameters),
|
||||
withParameterSchemas(inactiveJobID, nil),
|
||||
withWorkspaceTags(inactiveVersionID, nil),
|
||||
withProvisionerDaemons([]database.ProvisionerDaemon{}),
|
||||
withProvisionerDaemons([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow{}),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
|
||||
@@ -462,7 +462,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) {
|
||||
withRichParameters(initialBuildParameters),
|
||||
withParameterSchemas(inactiveJobID, nil),
|
||||
withWorkspaceTags(inactiveVersionID, nil),
|
||||
withProvisionerDaemons([]database.ProvisionerDaemon{}),
|
||||
withProvisionerDaemons([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow{}),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
|
||||
@@ -596,7 +596,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) {
|
||||
withRichParameters(initialBuildParameters),
|
||||
withParameterSchemas(activeJobID, nil),
|
||||
withWorkspaceTags(activeVersionID, nil),
|
||||
withProvisionerDaemons([]database.ProvisionerDaemon{}),
|
||||
withProvisionerDaemons([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow{}),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
|
||||
@@ -658,7 +658,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) {
|
||||
withRichParameters(initialBuildParameters),
|
||||
withParameterSchemas(activeJobID, nil),
|
||||
withWorkspaceTags(activeVersionID, nil),
|
||||
withProvisionerDaemons([]database.ProvisionerDaemon{}),
|
||||
withProvisionerDaemons([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow{}),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
|
||||
@@ -718,7 +718,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) {
|
||||
withRichParameters(initialBuildParameters),
|
||||
withParameterSchemas(activeJobID, nil),
|
||||
withWorkspaceTags(activeVersionID, nil),
|
||||
withProvisionerDaemons([]database.ProvisionerDaemon{}),
|
||||
withProvisionerDaemons([]database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow{}),
|
||||
|
||||
// Outputs
|
||||
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
|
||||
@@ -1009,8 +1009,8 @@ func expectBuildParameters(
|
||||
}
|
||||
}
|
||||
|
||||
func withProvisionerDaemons(provisionerDaemons []database.ProvisionerDaemon) func(mTx *dbmock.MockStore) {
|
||||
func withProvisionerDaemons(provisionerDaemons []database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow) func(mTx *dbmock.MockStore) {
|
||||
return func(mTx *dbmock.MockStore) {
|
||||
mTx.EXPECT().GetProvisionerDaemonsByOrganization(gomock.Any(), gomock.Any()).Return(provisionerDaemons, nil)
|
||||
mTx.EXPECT().GetEligibleProvisionerDaemonsByProvisionerJobIDs(gomock.Any(), gomock.Any()).Return(provisionerDaemons, nil)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user