Skip to content

Commit 3dcee5e

Browse files
committed
feat(cli): add provisioner list and provisioner jobs list
Closes #15191 Updates #15084 Supercedes #15940
1 parent 4bc3559 commit 3dcee5e

32 files changed

+857
-25
lines changed

cli/provisionerjobs.go

Lines changed: 120 additions & 0 deletions
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

Lines changed: 93 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy