Skip to content

Commit b437f27

Browse files
committed
feat: add provisioner key cli commands
1 parent 600d10c commit b437f27

File tree

2 files changed

+186
-0
lines changed

2 files changed

+186
-0
lines changed

enterprise/cli/provisionerdaemons.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@ func (r *RootCmd) provisionerDaemons() *serpent.Command {
3939
Handler: func(inv *serpent.Invocation) error {
4040
return inv.Command.HelpHandler(inv)
4141
},
42+
Aliases: []string{"provisioner"},
4243
Children: []*serpent.Command{
4344
r.provisionerDaemonStart(),
45+
r.provisionerKeys(),
4446
},
4547
}
4648

enterprise/cli/provisionerkeys.go

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
"time"
6+
7+
"github.com/google/uuid"
8+
"golang.org/x/xerrors"
9+
10+
agpl "github.com/coder/coder/v2/cli"
11+
"github.com/coder/coder/v2/cli/cliui"
12+
"github.com/coder/coder/v2/codersdk"
13+
"github.com/coder/pretty"
14+
"github.com/coder/serpent"
15+
)
16+
17+
func (r *RootCmd) provisionerKeys() *serpent.Command {
18+
cmd := &serpent.Command{
19+
Use: "keys",
20+
Short: "Manage provisioner keys",
21+
Handler: func(inv *serpent.Invocation) error {
22+
return inv.Command.HelpHandler(inv)
23+
},
24+
Aliases: []string{"key"},
25+
Children: []*serpent.Command{
26+
r.provisionerKeysCreate(),
27+
r.provisionerKeysList(),
28+
r.provisionerKeysDelete(),
29+
},
30+
}
31+
32+
return cmd
33+
}
34+
35+
func (r *RootCmd) provisionerKeysCreate() *serpent.Command {
36+
var (
37+
orgContext = agpl.NewOrganizationContext()
38+
)
39+
40+
client := new(codersdk.Client)
41+
cmd := &serpent.Command{
42+
Use: "create <name>",
43+
Short: "Create a new provisioner key",
44+
Middleware: serpent.Chain(
45+
serpent.RequireNArgs(1),
46+
r.InitClient(client),
47+
),
48+
Handler: func(inv *serpent.Invocation) error {
49+
ctx := inv.Context()
50+
51+
org, err := orgContext.Selected(inv, client)
52+
if err != nil {
53+
return xerrors.Errorf("current organization: %w", err)
54+
}
55+
56+
res, err := client.CreateProvisionerKey(ctx, org.ID, codersdk.CreateProvisionerKeyRequest{
57+
Name: inv.Args[0],
58+
})
59+
if err != nil {
60+
return xerrors.Errorf("create provisioner key: %w", err)
61+
}
62+
63+
_, _ = fmt.Fprintf(inv.Stdout, "Successfully created provisioner key %s!\n\n%s", pretty.Sprint(cliui.DefaultStyles.Keyword, inv.Args[0], res.Key))
64+
65+
return nil
66+
},
67+
}
68+
69+
cmd.Options = serpent.OptionSet{}
70+
71+
return cmd
72+
}
73+
74+
type provisionerKeysTableRow struct {
75+
// For json output:
76+
Key codersdk.ProvisionerKey `table:"-"`
77+
78+
// For table output:
79+
Name string `json:"-" table:"name,default_sort"`
80+
CreatedAt time.Time `json:"-" table:"created_at"`
81+
OrganizationID uuid.UUID `json:"-" table:"organization_id"`
82+
}
83+
84+
func provisionerKeysToRows(keys ...codersdk.ProvisionerKey) []provisionerKeysTableRow {
85+
rows := make([]provisionerKeysTableRow, 0, len(keys))
86+
for _, key := range keys {
87+
rows = append(rows, provisionerKeysTableRow{
88+
Name: key.Name,
89+
CreatedAt: key.CreatedAt,
90+
OrganizationID: key.OrganizationID,
91+
})
92+
}
93+
94+
return rows
95+
}
96+
97+
func (r *RootCmd) provisionerKeysList() *serpent.Command {
98+
var (
99+
orgContext = agpl.NewOrganizationContext()
100+
formatter = cliui.NewOutputFormatter(
101+
cliui.TableFormat([]provisionerKeysTableRow{}, nil),
102+
cliui.JSONFormat(),
103+
)
104+
)
105+
106+
client := new(codersdk.Client)
107+
cmd := &serpent.Command{
108+
Use: "list",
109+
Short: "List provisioner keys",
110+
Middleware: serpent.Chain(
111+
serpent.RequireNArgs(0),
112+
r.InitClient(client),
113+
),
114+
Handler: func(inv *serpent.Invocation) error {
115+
ctx := inv.Context()
116+
117+
org, err := orgContext.Selected(inv, client)
118+
if err != nil {
119+
return xerrors.Errorf("current organization: %w", err)
120+
}
121+
122+
keys, err := client.ListProvisionerKeys(ctx, org.ID)
123+
if err != nil {
124+
return xerrors.Errorf("list provisioner keys: %w", err)
125+
}
126+
127+
if len(keys) == 0 {
128+
_, _ = fmt.Fprintln(inv.Stdout, "No provisioner keys found")
129+
return nil
130+
}
131+
132+
rows := provisionerKeysToRows(keys...)
133+
out, err := formatter.Format(inv.Context(), rows)
134+
if err != nil {
135+
return xerrors.Errorf("display provisioner keys: %w", err)
136+
}
137+
138+
_, _ = fmt.Fprintln(inv.Stdout, out)
139+
140+
return nil
141+
},
142+
}
143+
144+
cmd.Options = serpent.OptionSet{}
145+
146+
return cmd
147+
}
148+
149+
func (r *RootCmd) provisionerKeysDelete() *serpent.Command {
150+
var (
151+
orgContext = agpl.NewOrganizationContext()
152+
)
153+
154+
client := new(codersdk.Client)
155+
cmd := &serpent.Command{
156+
Use: "delete <name>",
157+
Short: "Delete a provisioner key",
158+
Middleware: serpent.Chain(
159+
serpent.RequireNArgs(1),
160+
r.InitClient(client),
161+
),
162+
Handler: func(inv *serpent.Invocation) error {
163+
ctx := inv.Context()
164+
165+
org, err := orgContext.Selected(inv, client)
166+
if err != nil {
167+
return xerrors.Errorf("current organization: %w", err)
168+
}
169+
170+
err = client.DeleteProvisionerKey(ctx, org.ID, inv.Args[0])
171+
if err != nil {
172+
return xerrors.Errorf("delete provisioner key: %w", err)
173+
}
174+
175+
_, _ = fmt.Fprintf(inv.Stdout, "Successfully deleted provisioner key %s!", pretty.Sprint(cliui.DefaultStyles.Keyword, inv.Args[0]))
176+
177+
return nil
178+
},
179+
}
180+
181+
cmd.Options = serpent.OptionSet{}
182+
183+
return cmd
184+
}

0 commit comments

Comments
 (0)