diff --git a/cli/provisionerjobs.go b/cli/provisionerjobs.go
index 3ce7da20b7..3f441a1758 100644
--- a/cli/provisionerjobs.go
+++ b/cli/provisionerjobs.go
@@ -43,8 +43,9 @@ func (r *RootCmd) provisionerJobsList() *serpent.Command {
cliui.TableFormat([]provisionerJobRow{}, []string{"created at", "id", "type", "template display name", "status", "queue", "tags"}),
cliui.JSONFormat(),
)
- status []string
- limit int64
+ status []string
+ limit int64
+ initiator string
)
cmd := &serpent.Command{
@@ -65,9 +66,20 @@ func (r *RootCmd) provisionerJobsList() *serpent.Command {
return xerrors.Errorf("current organization: %w", err)
}
+ var initiatorID *uuid.UUID
+
+ if initiator != "" {
+ user, err := client.User(ctx, initiator)
+ if err != nil {
+ return xerrors.Errorf("initiator not found: %s", initiator)
+ }
+ initiatorID = &user.ID
+ }
+
jobs, err := client.OrganizationProvisionerJobs(ctx, org.ID, &codersdk.OrganizationProvisionerJobsOptions{
- Status: slice.StringEnums[codersdk.ProvisionerJobStatus](status),
- Limit: int(limit),
+ Status: slice.StringEnums[codersdk.ProvisionerJobStatus](status),
+ Limit: int(limit),
+ InitiatorID: initiatorID,
})
if err != nil {
return xerrors.Errorf("list provisioner jobs: %w", err)
@@ -122,6 +134,13 @@ func (r *RootCmd) provisionerJobsList() *serpent.Command {
Default: "50",
Value: serpent.Int64Of(&limit),
},
+ {
+ Flag: "initiator",
+ FlagShorthand: "i",
+ Env: "CODER_PROVISIONER_JOB_LIST_INITIATOR",
+ Description: "Filter by initiator (user ID or username).",
+ Value: serpent.StringOf(&initiator),
+ },
}...)
orgContext.AttachOptions(cmd)
diff --git a/cli/provisionerjobs_test.go b/cli/provisionerjobs_test.go
index 4db42e8e3c..57072a6156 100644
--- a/cli/provisionerjobs_test.go
+++ b/cli/provisionerjobs_test.go
@@ -5,6 +5,7 @@ import (
"database/sql"
"encoding/json"
"fmt"
+ "strings"
"testing"
"time"
@@ -26,33 +27,32 @@ import (
func TestProvisionerJobs(t *testing.T) {
t.Parallel()
- db, ps := dbtestutil.NewDB(t)
- client, _, coderdAPI := coderdtest.NewWithAPI(t, &coderdtest.Options{
- IncludeProvisionerDaemon: false,
- Database: db,
- Pubsub: ps,
- })
- owner := coderdtest.CreateFirstUser(t, client)
- templateAdminClient, templateAdmin := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.ScopedRoleOrgTemplateAdmin(owner.OrganizationID))
- memberClient, member := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
-
- // These CLI tests are related to provisioner job CRUD operations and as such
- // do not require the overhead of starting a provisioner. Other provisioner job
- // functionalities (acquisition etc.) are tested elsewhere.
- template := dbgen.Template(t, db, database.Template{
- OrganizationID: owner.OrganizationID,
- CreatedBy: owner.UserID,
- AllowUserCancelWorkspaceJobs: true,
- })
- version := dbgen.TemplateVersion(t, db, database.TemplateVersion{
- OrganizationID: owner.OrganizationID,
- CreatedBy: owner.UserID,
- TemplateID: uuid.NullUUID{UUID: template.ID, Valid: true},
- })
-
t.Run("Cancel", func(t *testing.T) {
t.Parallel()
+ db, ps := dbtestutil.NewDB(t)
+ client, _, coderdAPI := coderdtest.NewWithAPI(t, &coderdtest.Options{
+ IncludeProvisionerDaemon: false,
+ Database: db,
+ Pubsub: ps,
+ })
+ owner := coderdtest.CreateFirstUser(t, client)
+ templateAdminClient, templateAdmin := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.ScopedRoleOrgTemplateAdmin(owner.OrganizationID))
+ memberClient, member := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
+
+ // These CLI tests are related to provisioner job CRUD operations and as such
+ // do not require the overhead of starting a provisioner. Other provisioner job
+ // functionalities (acquisition etc.) are tested elsewhere.
+ template := dbgen.Template(t, db, database.Template{
+ OrganizationID: owner.OrganizationID,
+ CreatedBy: owner.UserID,
+ AllowUserCancelWorkspaceJobs: true,
+ })
+ version := dbgen.TemplateVersion(t, db, database.TemplateVersion{
+ OrganizationID: owner.OrganizationID,
+ CreatedBy: owner.UserID,
+ TemplateID: uuid.NullUUID{UUID: template.ID, Valid: true},
+ })
// Test helper to create a provisioner job of a given type with a given input.
prepareJob := func(t *testing.T, jobType database.ProvisionerJobType, input json.RawMessage) database.ProvisionerJob {
t.Helper()
@@ -178,4 +178,148 @@ func TestProvisionerJobs(t *testing.T) {
})
}
})
+
+ t.Run("List", func(t *testing.T) {
+ t.Parallel()
+
+ db, ps := dbtestutil.NewDB(t)
+ client, _, coderdAPI := coderdtest.NewWithAPI(t, &coderdtest.Options{
+ IncludeProvisionerDaemon: false,
+ Database: db,
+ Pubsub: ps,
+ })
+ owner := coderdtest.CreateFirstUser(t, client)
+ _, member := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
+
+ // These CLI tests are related to provisioner job CRUD operations and as such
+ // do not require the overhead of starting a provisioner. Other provisioner job
+ // functionalities (acquisition etc.) are tested elsewhere.
+ template := dbgen.Template(t, db, database.Template{
+ OrganizationID: owner.OrganizationID,
+ CreatedBy: owner.UserID,
+ AllowUserCancelWorkspaceJobs: true,
+ })
+ version := dbgen.TemplateVersion(t, db, database.TemplateVersion{
+ OrganizationID: owner.OrganizationID,
+ CreatedBy: owner.UserID,
+ TemplateID: uuid.NullUUID{UUID: template.ID, Valid: true},
+ })
+ // Create some test jobs
+ job1 := dbgen.ProvisionerJob(t, db, coderdAPI.Pubsub, database.ProvisionerJob{
+ OrganizationID: owner.OrganizationID,
+ InitiatorID: owner.UserID,
+ Type: database.ProvisionerJobTypeTemplateVersionImport,
+ Input: []byte(`{"template_version_id":"` + version.ID.String() + `"}`),
+ Tags: database.StringMap{provisionersdk.TagScope: provisionersdk.ScopeOrganization},
+ })
+
+ job2 := dbgen.ProvisionerJob(t, db, coderdAPI.Pubsub, database.ProvisionerJob{
+ OrganizationID: owner.OrganizationID,
+ InitiatorID: member.ID,
+ Type: database.ProvisionerJobTypeWorkspaceBuild,
+ Input: []byte(`{"workspace_build_id":"` + uuid.New().String() + `"}`),
+ Tags: database.StringMap{provisionersdk.TagScope: provisionersdk.ScopeOrganization},
+ })
+ // Test basic list command
+ t.Run("Basic", func(t *testing.T) {
+ t.Parallel()
+
+ inv, root := clitest.New(t, "provisioner", "jobs", "list")
+ clitest.SetupConfig(t, client, root)
+ var buf bytes.Buffer
+ inv.Stdout = &buf
+ err := inv.Run()
+ require.NoError(t, err)
+
+ // Should contain both jobs
+ output := buf.String()
+ assert.Contains(t, output, job1.ID.String())
+ assert.Contains(t, output, job2.ID.String())
+ })
+
+ // Test list with JSON output
+ t.Run("JSON", func(t *testing.T) {
+ t.Parallel()
+
+ inv, root := clitest.New(t, "provisioner", "jobs", "list", "--output", "json")
+ clitest.SetupConfig(t, client, root)
+ var buf bytes.Buffer
+ inv.Stdout = &buf
+ err := inv.Run()
+ require.NoError(t, err)
+
+ // Parse JSON output
+ var jobs []codersdk.ProvisionerJob
+ err = json.Unmarshal(buf.Bytes(), &jobs)
+ require.NoError(t, err)
+
+ // Should contain both jobs
+ jobIDs := make([]uuid.UUID, len(jobs))
+ for i, job := range jobs {
+ jobIDs[i] = job.ID
+ }
+ assert.Contains(t, jobIDs, job1.ID)
+ assert.Contains(t, jobIDs, job2.ID)
+ })
+
+ // Test list with limit
+ t.Run("Limit", func(t *testing.T) {
+ t.Parallel()
+
+ inv, root := clitest.New(t, "provisioner", "jobs", "list", "--limit", "1")
+ clitest.SetupConfig(t, client, root)
+ var buf bytes.Buffer
+ inv.Stdout = &buf
+ err := inv.Run()
+ require.NoError(t, err)
+
+ // Should contain at most 1 job
+ output := buf.String()
+ jobCount := 0
+ if strings.Contains(output, job1.ID.String()) {
+ jobCount++
+ }
+ if strings.Contains(output, job2.ID.String()) {
+ jobCount++
+ }
+ assert.LessOrEqual(t, jobCount, 1)
+ })
+
+ // Test list with initiator filter
+ t.Run("InitiatorFilter", func(t *testing.T) {
+ t.Parallel()
+
+ // Get owner user details to access username
+ ctx := testutil.Context(t, testutil.WaitShort)
+ ownerUser, err := client.User(ctx, owner.UserID.String())
+ require.NoError(t, err)
+
+ // Test filtering by initiator (using username)
+ inv, root := clitest.New(t, "provisioner", "jobs", "list", "--initiator", ownerUser.Username)
+ clitest.SetupConfig(t, client, root)
+ var buf bytes.Buffer
+ inv.Stdout = &buf
+ err = inv.Run()
+ require.NoError(t, err)
+
+ // Should only contain job1 (initiated by owner)
+ output := buf.String()
+ assert.Contains(t, output, job1.ID.String())
+ assert.NotContains(t, output, job2.ID.String())
+ })
+
+ // Test list with invalid user
+ t.Run("InvalidUser", func(t *testing.T) {
+ t.Parallel()
+
+ // Test with non-existent user
+ inv, root := clitest.New(t, "provisioner", "jobs", "list", "--initiator", "nonexistent-user")
+ clitest.SetupConfig(t, client, root)
+ var buf bytes.Buffer
+ inv.Stdout = &buf
+ err := inv.Run()
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "initiator not found: nonexistent-user")
+ })
+ })
}
diff --git a/cli/testdata/coder_list_--output_json.golden b/cli/testdata/coder_list_--output_json.golden
index 82b73f7b24..66afcf563d 100644
--- a/cli/testdata/coder_list_--output_json.golden
+++ b/cli/testdata/coder_list_--output_json.golden
@@ -45,6 +45,7 @@
"queue_position": 0,
"queue_size": 0,
"organization_id": "===========[first org ID]===========",
+ "initiator_id": "==========[first user ID]===========",
"input": {
"workspace_build_id": "========[workspace build ID]========"
},
diff --git a/cli/testdata/coder_provisioner_jobs_list_--help.golden b/cli/testdata/coder_provisioner_jobs_list_--help.golden
index 8e22f78e97..3a581bd880 100644
--- a/cli/testdata/coder_provisioner_jobs_list_--help.golden
+++ b/cli/testdata/coder_provisioner_jobs_list_--help.golden
@@ -11,9 +11,12 @@ OPTIONS:
-O, --org string, $CODER_ORGANIZATION
Select which organization (uuid or name) to use.
- -c, --column [id|created at|started at|completed at|canceled at|error|error code|status|worker id|worker name|file id|tags|queue position|queue size|organization id|template version id|workspace build id|type|available workers|template version name|template id|template name|template display name|template icon|workspace id|workspace name|logs overflowed|organization|queue] (default: created at,id,type,template display name,status,queue,tags)
+ -c, --column [id|created at|started at|completed at|canceled at|error|error code|status|worker id|worker name|file id|tags|queue position|queue size|organization id|initiator id|template version id|workspace build id|type|available workers|template version name|template id|template name|template display name|template icon|workspace id|workspace name|logs overflowed|organization|queue] (default: created at,id,type,template display name,status,queue,tags)
Columns to display in table output.
+ -i, --initiator string, $CODER_PROVISIONER_JOB_LIST_INITIATOR
+ Filter by initiator (user ID or username).
+
-l, --limit int, $CODER_PROVISIONER_JOB_LIST_LIMIT (default: 50)
Limit the number of jobs returned.
diff --git a/cli/testdata/coder_provisioner_jobs_list_--output_json.golden b/cli/testdata/coder_provisioner_jobs_list_--output_json.golden
index 6ccf672360..3ee6c25e34 100644
--- a/cli/testdata/coder_provisioner_jobs_list_--output_json.golden
+++ b/cli/testdata/coder_provisioner_jobs_list_--output_json.golden
@@ -15,6 +15,7 @@
"queue_position": 0,
"queue_size": 0,
"organization_id": "===========[first org ID]===========",
+ "initiator_id": "==========[first user ID]===========",
"input": {
"template_version_id": "============[version ID]============"
},
@@ -45,6 +46,7 @@
"queue_position": 0,
"queue_size": 0,
"organization_id": "===========[first org ID]===========",
+ "initiator_id": "==========[first user ID]===========",
"input": {
"workspace_build_id": "========[workspace build ID]========"
},
diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go
index b93c647dad..289e4c9a3f 100644
--- a/coderd/apidoc/docs.go
+++ b/coderd/apidoc/docs.go
@@ -3744,6 +3744,13 @@ const docTemplate = `{
"description": "Provisioner tags to filter by (JSON of the form {'tag1':'value1','tag2':'value2'})",
"name": "tags",
"in": "query"
+ },
+ {
+ "type": "string",
+ "format": "uuid",
+ "description": "Filter results by initiator",
+ "name": "initiator",
+ "in": "query"
}
],
"responses": {
@@ -15974,6 +15981,10 @@ const docTemplate = `{
"type": "string",
"format": "uuid"
},
+ "initiator_id": {
+ "type": "string",
+ "format": "uuid"
+ },
"input": {
"$ref": "#/definitions/codersdk.ProvisionerJobInput"
},
diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json
index 731e1720c0..4b3d4c86aa 100644
--- a/coderd/apidoc/swagger.json
+++ b/coderd/apidoc/swagger.json
@@ -3299,6 +3299,13 @@
"description": "Provisioner tags to filter by (JSON of the form {'tag1':'value1','tag2':'value2'})",
"name": "tags",
"in": "query"
+ },
+ {
+ "type": "string",
+ "format": "uuid",
+ "description": "Filter results by initiator",
+ "name": "initiator",
+ "in": "query"
}
],
"responses": {
@@ -14532,6 +14539,10 @@
"type": "string",
"format": "uuid"
},
+ "initiator_id": {
+ "type": "string",
+ "format": "uuid"
+ },
"input": {
"$ref": "#/definitions/codersdk.ProvisionerJobInput"
},
diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go
index 730d5f3198..39350ad948 100644
--- a/coderd/database/dbauthz/dbauthz_test.go
+++ b/coderd/database/dbauthz/dbauthz_test.go
@@ -2484,10 +2484,12 @@ func (s *MethodTestSuite) TestExtraMethods() {
ds, err := db.GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisioner(context.Background(), database.GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerParams{
OrganizationID: org.ID,
+ InitiatorID: uuid.Nil,
})
s.NoError(err, "get provisioner jobs by org")
check.Args(database.GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerParams{
OrganizationID: org.ID,
+ InitiatorID: uuid.Nil,
}).Asserts(j1, policy.ActionRead, j2, policy.ActionRead).Returns(ds)
}))
}
diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go
index 6bf1a3e25d..3612375b8b 100644
--- a/coderd/database/queries.sql.go
+++ b/coderd/database/queries.sql.go
@@ -9834,6 +9834,7 @@ WHERE
AND (COALESCE(array_length($2::uuid[], 1), 0) = 0 OR pj.id = ANY($2::uuid[]))
AND (COALESCE(array_length($3::provisioner_job_status[], 1), 0) = 0 OR pj.job_status = ANY($3::provisioner_job_status[]))
AND ($4::tagset = 'null'::tagset OR provisioner_tagset_contains(pj.tags::tagset, $4::tagset))
+ AND ($5::uuid = '00000000-0000-0000-0000-000000000000'::uuid OR pj.initiator_id = $5::uuid)
GROUP BY
pj.id,
qp.queue_position,
@@ -9849,7 +9850,7 @@ GROUP BY
ORDER BY
pj.created_at DESC
LIMIT
- $5::int
+ $6::int
`
type GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerParams struct {
@@ -9857,6 +9858,7 @@ type GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerPar
IDs []uuid.UUID `db:"ids" json:"ids"`
Status []ProvisionerJobStatus `db:"status" json:"status"`
Tags StringMap `db:"tags" json:"tags"`
+ InitiatorID uuid.UUID `db:"initiator_id" json:"initiator_id"`
Limit sql.NullInt32 `db:"limit" json:"limit"`
}
@@ -9881,6 +9883,7 @@ func (q *sqlQuerier) GetProvisionerJobsByOrganizationAndStatusWithQueuePositionA
pq.Array(arg.IDs),
pq.Array(arg.Status),
arg.Tags,
+ arg.InitiatorID,
arg.Limit,
)
if err != nil {
diff --git a/coderd/database/queries/provisionerjobs.sql b/coderd/database/queries/provisionerjobs.sql
index dfc95a0bb4..02d67d628a 100644
--- a/coderd/database/queries/provisionerjobs.sql
+++ b/coderd/database/queries/provisionerjobs.sql
@@ -224,6 +224,7 @@ WHERE
AND (COALESCE(array_length(@ids::uuid[], 1), 0) = 0 OR pj.id = ANY(@ids::uuid[]))
AND (COALESCE(array_length(@status::provisioner_job_status[], 1), 0) = 0 OR pj.job_status = ANY(@status::provisioner_job_status[]))
AND (@tags::tagset = 'null'::tagset OR provisioner_tagset_contains(pj.tags::tagset, @tags::tagset))
+ AND (@initiator_id::uuid = '00000000-0000-0000-0000-000000000000'::uuid OR pj.initiator_id = @initiator_id::uuid)
GROUP BY
pj.id,
qp.queue_position,
diff --git a/coderd/provisionerjobs.go b/coderd/provisionerjobs.go
index e9ab526098..4ba923dae2 100644
--- a/coderd/provisionerjobs.go
+++ b/coderd/provisionerjobs.go
@@ -76,6 +76,7 @@ func (api *API) provisionerJob(rw http.ResponseWriter, r *http.Request) {
// @Param ids query []string false "Filter results by job IDs" format(uuid)
// @Param status query codersdk.ProvisionerJobStatus false "Filter results by status" enums(pending,running,succeeded,canceling,canceled,failed)
// @Param tags query object false "Provisioner tags to filter by (JSON of the form {'tag1':'value1','tag2':'value2'})"
+// @Param initiator query string false "Filter results by initiator" format(uuid)
// @Success 200 {array} codersdk.ProvisionerJob
// @Router /organizations/{organization}/provisionerjobs [get]
func (api *API) provisionerJobs(rw http.ResponseWriter, r *http.Request) {
@@ -110,6 +111,7 @@ func (api *API) handleAuthAndFetchProvisionerJobs(rw http.ResponseWriter, r *htt
ids = p.UUIDs(qp, nil, "ids")
}
tags := p.JSONStringMap(qp, database.StringMap{}, "tags")
+ initiatorID := p.UUID(qp, uuid.Nil, "initiator_id")
p.ErrorExcessParams(qp)
if len(p.Errors) > 0 {
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
@@ -125,6 +127,7 @@ func (api *API) handleAuthAndFetchProvisionerJobs(rw http.ResponseWriter, r *htt
Limit: sql.NullInt32{Int32: limit, Valid: limit > 0},
IDs: ids,
Tags: tags,
+ InitiatorID: initiatorID,
})
if err != nil {
if httpapi.Is404Error(err) {
@@ -355,6 +358,7 @@ func convertProvisionerJob(pj database.GetProvisionerJobsByIDsWithQueuePositionR
job := codersdk.ProvisionerJob{
ID: provisionerJob.ID,
OrganizationID: provisionerJob.OrganizationID,
+ InitiatorID: provisionerJob.InitiatorID,
CreatedAt: provisionerJob.CreatedAt,
Type: codersdk.ProvisionerJobType(provisionerJob.Type),
Error: provisionerJob.Error.String,
diff --git a/coderd/provisionerjobs_test.go b/coderd/provisionerjobs_test.go
index 98da3ae558..829c72aa4d 100644
--- a/coderd/provisionerjobs_test.go
+++ b/coderd/provisionerjobs_test.go
@@ -58,6 +58,8 @@ func TestProvisionerJobs(t *testing.T) {
StartedAt: sql.NullTime{Time: dbtime.Now(), Valid: true},
Type: database.ProvisionerJobTypeWorkspaceBuild,
Input: json.RawMessage(`{"workspace_build_id":"` + wbID.String() + `"}`),
+ InitiatorID: member.ID,
+ Tags: database.StringMap{"initiatorTest": "true"},
})
dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{
ID: wbID,
@@ -71,6 +73,7 @@ func TestProvisionerJobs(t *testing.T) {
dbgen.ProvisionerJob(t, db, nil, database.ProvisionerJob{
OrganizationID: owner.OrganizationID,
Tags: database.StringMap{"count": strconv.Itoa(i)},
+ InitiatorID: owner.UserID,
})
}
@@ -165,6 +168,94 @@ func TestProvisionerJobs(t *testing.T) {
require.Len(t, jobs, 1)
})
+ t.Run("Initiator", func(t *testing.T) {
+ t.Parallel()
+ ctx := testutil.Context(t, testutil.WaitMedium)
+
+ jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
+ InitiatorID: &member.ID,
+ })
+ require.NoError(t, err)
+ require.GreaterOrEqual(t, len(jobs), 1)
+ require.Equal(t, member.ID, jobs[0].InitiatorID)
+ })
+
+ t.Run("InitiatorWithOtherFilters", func(t *testing.T) {
+ t.Parallel()
+ ctx := testutil.Context(t, testutil.WaitMedium)
+
+ // Test filtering by initiator ID combined with status filter
+ jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
+ InitiatorID: &owner.UserID,
+ Status: []codersdk.ProvisionerJobStatus{codersdk.ProvisionerJobSucceeded},
+ })
+ require.NoError(t, err)
+
+ // Verify all returned jobs have the correct initiator and status
+ for _, job := range jobs {
+ require.Equal(t, owner.UserID, job.InitiatorID)
+ require.Equal(t, codersdk.ProvisionerJobSucceeded, job.Status)
+ }
+ })
+
+ t.Run("InitiatorWithLimit", func(t *testing.T) {
+ t.Parallel()
+ ctx := testutil.Context(t, testutil.WaitMedium)
+
+ // Test filtering by initiator ID with limit
+ jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
+ InitiatorID: &owner.UserID,
+ Limit: 1,
+ })
+ require.NoError(t, err)
+ require.Len(t, jobs, 1)
+
+ // Verify the returned job has the correct initiator
+ require.Equal(t, owner.UserID, jobs[0].InitiatorID)
+ })
+
+ t.Run("InitiatorWithTags", func(t *testing.T) {
+ t.Parallel()
+ ctx := testutil.Context(t, testutil.WaitMedium)
+
+ // Test filtering by initiator ID combined with tags
+ jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
+ InitiatorID: &member.ID,
+ Tags: map[string]string{"initiatorTest": "true"},
+ })
+ require.NoError(t, err)
+ require.Len(t, jobs, 1)
+
+ // Verify the returned job has the correct initiator and tags
+ require.Equal(t, member.ID, jobs[0].InitiatorID)
+ require.Equal(t, "true", jobs[0].Tags["initiatorTest"])
+ })
+
+ t.Run("InitiatorNotFound", func(t *testing.T) {
+ t.Parallel()
+ ctx := testutil.Context(t, testutil.WaitMedium)
+
+ // Test with non-existent initiator ID
+ nonExistentID := uuid.New()
+ jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
+ InitiatorID: &nonExistentID,
+ })
+ require.NoError(t, err)
+ require.Len(t, jobs, 0)
+ })
+
+ t.Run("InitiatorNil", func(t *testing.T) {
+ t.Parallel()
+ ctx := testutil.Context(t, testutil.WaitMedium)
+
+ // Test with nil initiator ID (should return all jobs)
+ jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
+ InitiatorID: nil,
+ })
+ require.NoError(t, err)
+ require.GreaterOrEqual(t, len(jobs), 50) // Should return all jobs (up to default limit)
+ })
+
t.Run("Limit", func(t *testing.T) {
t.Parallel()
ctx := testutil.Context(t, testutil.WaitMedium)
@@ -185,6 +276,17 @@ func TestProvisionerJobs(t *testing.T) {
require.Error(t, err)
require.Len(t, jobs, 0)
})
+
+ t.Run("MemberDeniedWithInitiator", func(t *testing.T) {
+ t.Parallel()
+ ctx := testutil.Context(t, testutil.WaitMedium)
+ // Member should not be able to access jobs even with initiator filter
+ jobs, err := memberClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
+ InitiatorID: &member.ID,
+ })
+ require.Error(t, err)
+ require.Len(t, jobs, 0)
+ })
})
// Ensures that when a provisioner job is in the succeeded state,
diff --git a/codersdk/organizations.go b/codersdk/organizations.go
index bca87c7bd4..291bb9ac1b 100644
--- a/codersdk/organizations.go
+++ b/codersdk/organizations.go
@@ -397,10 +397,11 @@ func (c *Client) OrganizationProvisionerDaemons(ctx context.Context, organizatio
}
type OrganizationProvisionerJobsOptions struct {
- Limit int
- IDs []uuid.UUID
- Status []ProvisionerJobStatus
- Tags map[string]string
+ Limit int
+ IDs []uuid.UUID
+ Status []ProvisionerJobStatus
+ Tags map[string]string
+ InitiatorID *uuid.UUID
}
func (c *Client) OrganizationProvisionerJobs(ctx context.Context, organizationID uuid.UUID, opts *OrganizationProvisionerJobsOptions) ([]ProvisionerJob, error) {
@@ -422,6 +423,9 @@ func (c *Client) OrganizationProvisionerJobs(ctx context.Context, organizationID
}
qp.Add("tags", string(tagsRaw))
}
+ if opts.InitiatorID != nil {
+ qp.Add("initiator_id", opts.InitiatorID.String())
+ }
}
res, err := c.Request(ctx, http.MethodGet,
diff --git a/codersdk/provisionerdaemons.go b/codersdk/provisionerdaemons.go
index b3cefa0911..19f8cae546 100644
--- a/codersdk/provisionerdaemons.go
+++ b/codersdk/provisionerdaemons.go
@@ -198,6 +198,7 @@ type ProvisionerJob struct {
QueuePosition int `json:"queue_position" table:"queue position"`
QueueSize int `json:"queue_size" table:"queue size"`
OrganizationID uuid.UUID `json:"organization_id" format:"uuid" table:"organization id"`
+ InitiatorID uuid.UUID `json:"initiator_id" format:"uuid" table:"initiator id"`
Input ProvisionerJobInput `json:"input" table:"input,recursive_inline"`
Type ProvisionerJobType `json:"type" table:"type"`
AvailableWorkers []uuid.UUID `json:"available_workers,omitempty" format:"uuid" table:"available workers"`
diff --git a/docs/reference/api/builds.md b/docs/reference/api/builds.md
index 232509052b..41df0b9efa 100644
--- a/docs/reference/api/builds.md
+++ b/docs/reference/api/builds.md
@@ -48,6 +48,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -288,6 +289,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild} \
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1019,6 +1021,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/sta
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1332,6 +1335,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace}/builds \
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1551,6 +1555,7 @@ Status Code **200**
| `»» error_code` | [codersdk.JobErrorCode](schemas.md#codersdkjoberrorcode) | false | | |
| `»» file_id` | string(uuid) | false | | |
| `»» id` | string(uuid) | false | | |
+| `»» initiator_id` | string(uuid) | false | | |
| `»» input` | [codersdk.ProvisionerJobInput](schemas.md#codersdkprovisionerjobinput) | false | | |
| `»»» error` | string | false | | |
| `»»» template_version_id` | string(uuid) | false | | |
@@ -1829,6 +1834,7 @@ curl -X POST http://coder-server:8080/api/v2/workspaces/{workspace}/builds \
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
diff --git a/docs/reference/api/organizations.md b/docs/reference/api/organizations.md
index d418a1fcba..ffd6f78405 100644
--- a/docs/reference/api/organizations.md
+++ b/docs/reference/api/organizations.md
@@ -366,6 +366,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/provisi
| `ids` | query | array(uuid) | false | Filter results by job IDs |
| `status` | query | string | false | Filter results by status |
| `tags` | query | object | false | Provisioner tags to filter by (JSON of the form {'tag1':'value1','tag2':'value2'}) |
+| `initiator` | query | string(uuid) | false | Filter results by initiator |
#### Enumerated Values
@@ -402,6 +403,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/provisi
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -454,6 +456,7 @@ Status Code **200**
| `» error_code` | [codersdk.JobErrorCode](schemas.md#codersdkjoberrorcode) | false | | |
| `» file_id` | string(uuid) | false | | |
| `» id` | string(uuid) | false | | |
+| `» initiator_id` | string(uuid) | false | | |
| `» input` | [codersdk.ProvisionerJobInput](schemas.md#codersdkprovisionerjobinput) | false | | |
| `»» error` | string | false | | |
| `»» template_version_id` | string(uuid) | false | | |
@@ -531,6 +534,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/provisi
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md
index 98324941a1..33cb280ae1 100644
--- a/docs/reference/api/schemas.md
+++ b/docs/reference/api/schemas.md
@@ -6390,6 +6390,7 @@ Only certain features set these fields: - FeatureManagedAgentLimit|
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -6432,6 +6433,7 @@ Only certain features set these fields: - FeatureManagedAgentLimit|
| `error_code` | [codersdk.JobErrorCode](#codersdkjoberrorcode) | false | | |
| `file_id` | string | false | | |
| `id` | string | false | | |
+| `initiator_id` | string | false | | |
| `input` | [codersdk.ProvisionerJobInput](#codersdkprovisionerjobinput) | false | | |
| `logs_overflowed` | boolean | false | | |
| `metadata` | [codersdk.ProvisionerJobMetadata](#codersdkprovisionerjobmetadata) | false | | |
@@ -8118,6 +8120,7 @@ Restarts will only happen on weekdays in this list on weeks which line up with W
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -9386,6 +9389,7 @@ If the schedule is empty, the user will be updated to use the default schedule.|
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -10553,6 +10557,7 @@ If the schedule is empty, the user will be updated to use the default schedule.|
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -11389,6 +11394,7 @@ If the schedule is empty, the user will be updated to use the default schedule.|
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
diff --git a/docs/reference/api/templates.md b/docs/reference/api/templates.md
index efc59cf7b5..9d69949ac7 100644
--- a/docs/reference/api/templates.md
+++ b/docs/reference/api/templates.md
@@ -475,6 +475,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -575,6 +576,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -699,6 +701,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1306,6 +1309,7 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/versions \
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1382,6 +1386,7 @@ Status Code **200**
| `»» error_code` | [codersdk.JobErrorCode](schemas.md#codersdkjoberrorcode) | false | | |
| `»» file_id` | string(uuid) | false | | |
| `»» id` | string(uuid) | false | | |
+| `»» initiator_id` | string(uuid) | false | | |
| `»» input` | [codersdk.ProvisionerJobInput](schemas.md#codersdkprovisionerjobinput) | false | | |
| `»»» error` | string | false | | |
| `»»» template_version_id` | string(uuid) | false | | |
@@ -1589,6 +1594,7 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/versions/{templ
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1665,6 +1671,7 @@ Status Code **200**
| `»» error_code` | [codersdk.JobErrorCode](schemas.md#codersdkjoberrorcode) | false | | |
| `»» file_id` | string(uuid) | false | | |
| `»» id` | string(uuid) | false | | |
+| `»» initiator_id` | string(uuid) | false | | |
| `»» input` | [codersdk.ProvisionerJobInput](schemas.md#codersdkprovisionerjobinput) | false | | |
| `»»» error` | string | false | | |
| `»»» template_version_id` | string(uuid) | false | | |
@@ -1762,6 +1769,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion} \
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1871,6 +1879,7 @@ curl -X PATCH http://coder-server:8080/api/v2/templateversions/{templateversion}
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -2069,6 +2078,7 @@ curl -X POST http://coder-server:8080/api/v2/templateversions/{templateversion}/
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -2143,6 +2153,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/d
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
diff --git a/docs/reference/api/workspaces.md b/docs/reference/api/workspaces.md
index 455fefcb57..e2a95613ed 100644
--- a/docs/reference/api/workspaces.md
+++ b/docs/reference/api/workspaces.md
@@ -103,6 +103,7 @@ of the template will be used.
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -393,6 +394,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -708,6 +710,7 @@ of the template will be used.
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1001,6 +1004,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces \
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1275,6 +1279,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace} \
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1824,6 +1829,7 @@ curl -X PUT http://coder-server:8080/api/v2/workspaces/{workspace}/dormant \
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
diff --git a/docs/reference/cli/provisioner_jobs_list.md b/docs/reference/cli/provisioner_jobs_list.md
index a0bff8554d..0167dd467d 100644
--- a/docs/reference/cli/provisioner_jobs_list.md
+++ b/docs/reference/cli/provisioner_jobs_list.md
@@ -34,6 +34,15 @@ Filter by job status.
Limit the number of jobs returned.
+### -i, --initiator
+
+| | |
+|-------------|----------------------------------------------------|
+| Type | string |
+| Environment | $CODER_PROVISIONER_JOB_LIST_INITIATOR |
+
+Filter by initiator (user ID or username).
+
### -O, --org
| | |
@@ -45,10 +54,10 @@ Select which organization (uuid or name) to use.
### -c, --column
-| | |
-|---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| Type | [id\|created at\|started at\|completed at\|canceled at\|error\|error code\|status\|worker id\|worker name\|file id\|tags\|queue position\|queue size\|organization id\|template version id\|workspace build id\|type\|available workers\|template version name\|template id\|template name\|template display name\|template icon\|workspace id\|workspace name\|logs overflowed\|organization\|queue] |
-| Default | created at,id,type,template display name,status,queue,tags |
+| | |
+|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Type | [id\|created at\|started at\|completed at\|canceled at\|error\|error code\|status\|worker id\|worker name\|file id\|tags\|queue position\|queue size\|organization id\|initiator id\|template version id\|workspace build id\|type\|available workers\|template version name\|template id\|template name\|template display name\|template icon\|workspace id\|workspace name\|logs overflowed\|organization\|queue] |
+| Default | created at,id,type,template display name,status,queue,tags |
Columns to display in table output.
diff --git a/enterprise/cli/testdata/coder_provisioner_jobs_list_--help.golden b/enterprise/cli/testdata/coder_provisioner_jobs_list_--help.golden
index 8e22f78e97..3a581bd880 100644
--- a/enterprise/cli/testdata/coder_provisioner_jobs_list_--help.golden
+++ b/enterprise/cli/testdata/coder_provisioner_jobs_list_--help.golden
@@ -11,9 +11,12 @@ OPTIONS:
-O, --org string, $CODER_ORGANIZATION
Select which organization (uuid or name) to use.
- -c, --column [id|created at|started at|completed at|canceled at|error|error code|status|worker id|worker name|file id|tags|queue position|queue size|organization id|template version id|workspace build id|type|available workers|template version name|template id|template name|template display name|template icon|workspace id|workspace name|logs overflowed|organization|queue] (default: created at,id,type,template display name,status,queue,tags)
+ -c, --column [id|created at|started at|completed at|canceled at|error|error code|status|worker id|worker name|file id|tags|queue position|queue size|organization id|initiator id|template version id|workspace build id|type|available workers|template version name|template id|template name|template display name|template icon|workspace id|workspace name|logs overflowed|organization|queue] (default: created at,id,type,template display name,status,queue,tags)
Columns to display in table output.
+ -i, --initiator string, $CODER_PROVISIONER_JOB_LIST_INITIATOR
+ Filter by initiator (user ID or username).
+
-l, --limit int, $CODER_PROVISIONER_JOB_LIST_LIMIT (default: 50)
Limit the number of jobs returned.
diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts
index 0519c9c136..e7c612078b 100644
--- a/site/src/api/typesGenerated.ts
+++ b/site/src/api/typesGenerated.ts
@@ -2060,6 +2060,7 @@ export interface OrganizationProvisionerJobsOptions {
readonly IDs: readonly string[];
readonly Status: readonly ProvisionerJobStatus[];
readonly Tags: Record;
+ readonly InitiatorID: string | null;
}
// From codersdk/idpsync.go
@@ -2379,6 +2380,7 @@ export interface ProvisionerJob {
readonly queue_position: number;
readonly queue_size: number;
readonly organization_id: string;
+ readonly initiator_id: string;
readonly input: ProvisionerJobInput;
readonly type: ProvisionerJobType;
readonly available_workers?: readonly string[];
diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts
index 19c414bdd3..0b8d87f811 100644
--- a/site/src/testHelpers/entities.ts
+++ b/site/src/testHelpers/entities.ts
@@ -679,6 +679,7 @@ export const MockProvisionerJob: TypesGen.ProvisionerJob = {
status: "succeeded",
file_id: MockOrganization.id,
completed_at: "2022-05-17T17:39:01.382927298Z",
+ initiator_id: MockUserMember.id,
tags: {
scope: "organization",
owner: "",