Skip to content

Commit 8726bd9

Browse files
committed
feat(cli): add provisioner list and provisioner jobs list
Closes #15191 Updates #15084 Supercedes #15940
1 parent 5633448 commit 8726bd9

32 files changed

+857
-25
lines changed

cli/provisionerjobs.go

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
6+
"golang.org/x/xerrors"
7+
8+
"github.com/coder/coder/v2/cli/cliui"
9+
"github.com/coder/coder/v2/coderd/util/slice"
10+
"github.com/coder/coder/v2/codersdk"
11+
"github.com/coder/serpent"
12+
)
13+
14+
func (r *RootCmd) provisionerJobs() *serpent.Command {
15+
cmd := &serpent.Command{
16+
Use: "jobs",
17+
Short: "View and manage provisioner jobs",
18+
Handler: func(inv *serpent.Invocation) error {
19+
return inv.Command.HelpHandler(inv)
20+
},
21+
Aliases: []string{"job"},
22+
Children: []*serpent.Command{
23+
r.provisionerJobsList(),
24+
},
25+
}
26+
return cmd
27+
}
28+
29+
func (r *RootCmd) provisionerJobsList() *serpent.Command {
30+
type provisionerJobRow struct {
31+
codersdk.ProvisionerJob `table:"provisioner_job,recursive_inline"`
32+
OrganizationName string `json:"organization_name" table:"organization"`
33+
Queue string `json:"-" table:"queue"`
34+
}
35+
36+
var (
37+
client = new(codersdk.Client)
38+
orgContext = NewOrganizationContext()
39+
formatter = cliui.NewOutputFormatter(
40+
cliui.TableFormat([]provisionerJobRow{}, []string{"created at", "id", "organization", "status", "type", "queue", "tags"}),
41+
cliui.JSONFormat(),
42+
)
43+
status []string
44+
limit int64
45+
)
46+
47+
cmd := &serpent.Command{
48+
Use: "list",
49+
Short: "List provisioner jobs",
50+
Aliases: []string{"ls"},
51+
Middleware: serpent.Chain(
52+
serpent.RequireNArgs(0),
53+
r.InitClient(client),
54+
),
55+
Handler: func(inv *serpent.Invocation) error {
56+
ctx := inv.Context()
57+
org, err := orgContext.Selected(inv, client)
58+
if err != nil {
59+
return xerrors.Errorf("current organization: %w", err)
60+
}
61+
62+
jobs, err := client.OrganizationProvisionerJobs(ctx, org.ID, &codersdk.OrganizationProvisionerJobsOptions{
63+
Status: slice.ToStringEnums[codersdk.ProvisionerJobStatus](status),
64+
Limit: int(limit),
65+
})
66+
if err != nil {
67+
return xerrors.Errorf("list provisioner jobs: %w", err)
68+
}
69+
70+
if len(jobs) == 0 {
71+
_, _ = fmt.Fprintln(inv.Stdout, "No provisioner jobs found")
72+
return nil
73+
}
74+
75+
var rows []provisionerJobRow
76+
for _, job := range jobs {
77+
row := provisionerJobRow{
78+
ProvisionerJob: job,
79+
OrganizationName: org.HumanName(),
80+
}
81+
if job.Status == codersdk.ProvisionerJobPending {
82+
row.Queue = fmt.Sprintf("%d/%d", job.QueuePosition, job.QueueSize)
83+
}
84+
rows = append(rows, row)
85+
}
86+
87+
out, err := formatter.Format(ctx, rows)
88+
if err != nil {
89+
return xerrors.Errorf("display provisioner daemons: %w", err)
90+
}
91+
92+
_, _ = fmt.Fprintln(inv.Stdout, out)
93+
94+
return nil
95+
},
96+
}
97+
98+
cmd.Options = append(cmd.Options, []serpent.Option{
99+
{
100+
Flag: "status",
101+
FlagShorthand: "s",
102+
Env: "CODER_PROVISIONER_JOB_LIST_STATUS",
103+
Description: "Filter by job status.",
104+
Value: serpent.EnumArrayOf(&status, slice.ToStrings(codersdk.ProvisionerJobStatusEnums())...),
105+
},
106+
{
107+
Flag: "limit",
108+
FlagShorthand: "l",
109+
Env: "CODER_PROVISIONER_JOB_LIST_LIMIT",
110+
Description: "Limit the number of jobs returned.",
111+
Default: "50",
112+
Value: serpent.Int64Of(&limit),
113+
},
114+
}...)
115+
116+
orgContext.AttachOptions(cmd)
117+
formatter.AttachOptions(&cmd.Options)
118+
119+
return cmd
120+
}

cli/provisioners.go

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
6+
"golang.org/x/xerrors"
7+
8+
"github.com/coder/coder/v2/cli/cliui"
9+
"github.com/coder/coder/v2/codersdk"
10+
"github.com/coder/serpent"
11+
)
12+
13+
func (r *RootCmd) Provisioners() *serpent.Command {
14+
cmd := &serpent.Command{
15+
Use: "provisioner",
16+
Short: "View and manage provisioner daemons and jobs",
17+
Handler: func(inv *serpent.Invocation) error {
18+
return inv.Command.HelpHandler(inv)
19+
},
20+
Aliases: []string{"provisioners"},
21+
Children: []*serpent.Command{
22+
r.provisionerList(),
23+
r.provisionerJobs(),
24+
},
25+
}
26+
27+
return cmd
28+
}
29+
30+
func (r *RootCmd) provisionerList() *serpent.Command {
31+
type provisionerDaemonRow struct {
32+
codersdk.ProvisionerDaemonWithStatus `table:"provisioner_daemon,recursive_inline"`
33+
OrganizationName string `json:"organization_name" table:"organization"`
34+
}
35+
var (
36+
client = new(codersdk.Client)
37+
orgContext = NewOrganizationContext()
38+
formatter = cliui.NewOutputFormatter(
39+
cliui.TableFormat([]provisionerDaemonRow{}, []string{"name", "organization", "status", "key name", "created at", "last seen at", "version", "tags"}),
40+
cliui.JSONFormat(),
41+
)
42+
)
43+
44+
cmd := &serpent.Command{
45+
Use: "list",
46+
Short: "List provisioner daemons in an organization",
47+
Aliases: []string{"ls"},
48+
Middleware: serpent.Chain(
49+
serpent.RequireNArgs(0),
50+
r.InitClient(client),
51+
),
52+
Handler: func(inv *serpent.Invocation) error {
53+
ctx := inv.Context()
54+
55+
org, err := orgContext.Selected(inv, client)
56+
if err != nil {
57+
return xerrors.Errorf("current organization: %w", err)
58+
}
59+
60+
daemons, err := client.OrganizationProvisionerDaemons(ctx, org.ID, nil)
61+
if err != nil {
62+
return xerrors.Errorf("list provisioner daemons: %w", err)
63+
}
64+
65+
if len(daemons) == 0 {
66+
_, _ = fmt.Fprintln(inv.Stdout, "No provisioner daemons found")
67+
return nil
68+
}
69+
70+
var rows []provisionerDaemonRow
71+
for _, daemon := range daemons {
72+
rows = append(rows, provisionerDaemonRow{
73+
ProvisionerDaemonWithStatus: daemon,
74+
OrganizationName: org.HumanName(),
75+
})
76+
}
77+
78+
out, err := formatter.Format(ctx, rows)
79+
if err != nil {
80+
return xerrors.Errorf("display provisioner daemons: %w", err)
81+
}
82+
83+
_, _ = fmt.Fprintln(inv.Stdout, out)
84+
85+
return nil
86+
},
87+
}
88+
89+
orgContext.AttachOptions(cmd)
90+
formatter.AttachOptions(&cmd.Options)
91+
92+
return cmd
93+
}

0 commit comments

Comments
 (0)