package cli import ( "fmt" "strings" "golang.org/x/xerrors" agpl "github.com/coder/coder/v2/cli" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" "github.com/coder/pretty" "github.com/coder/serpent" ) func (r *RootCmd) provisionerKeys() *serpent.Command { cmd := &serpent.Command{ Use: "keys", Short: "Manage provisioner keys", Handler: func(inv *serpent.Invocation) error { return inv.Command.HelpHandler(inv) }, Aliases: []string{"key"}, Children: []*serpent.Command{ r.provisionerKeysCreate(), r.provisionerKeysList(), r.provisionerKeysDelete(), }, } return cmd } func (r *RootCmd) provisionerKeysCreate() *serpent.Command { var ( orgContext = agpl.NewOrganizationContext() rawTags []string ) cmd := &serpent.Command{ Use: "create ", Short: "Create a new provisioner key", Middleware: serpent.Chain( serpent.RequireNArgs(1), ), Handler: func(inv *serpent.Invocation) error { ctx := inv.Context() client, err := r.InitClient(inv) if err != nil { return err } org, err := orgContext.Selected(inv, client) if err != nil { return xerrors.Errorf("current organization: %w", err) } tags, err := agpl.ParseProvisionerTags(rawTags) if err != nil { return err } res, err := client.CreateProvisionerKey(ctx, org.ID, codersdk.CreateProvisionerKeyRequest{ Name: inv.Args[0], Tags: tags, }) if err != nil { return xerrors.Errorf("create provisioner key: %w", err) } _, _ = fmt.Fprintf( inv.Stdout, "Successfully created provisioner key %s! Save this authentication token, it will not be shown again.\n\n%s\n", pretty.Sprint(cliui.DefaultStyles.Keyword, strings.ToLower(inv.Args[0])), pretty.Sprint(cliui.DefaultStyles.Keyword, res.Key), ) return nil }, } cmd.Options = serpent.OptionSet{ { Flag: "tag", FlagShorthand: "t", Env: "CODER_PROVISIONERD_TAGS", Description: "Tags to filter provisioner jobs by.", Value: serpent.StringArrayOf(&rawTags), }, } orgContext.AttachOptions(cmd) return cmd } func (r *RootCmd) provisionerKeysList() *serpent.Command { var ( orgContext = agpl.NewOrganizationContext() formatter = cliui.NewOutputFormatter( cliui.TableFormat([]codersdk.ProvisionerKey{}, []string{"created at", "name", "tags"}), cliui.JSONFormat(), ) ) cmd := &serpent.Command{ Use: "list", Short: "List provisioner keys in an organization", Aliases: []string{"ls"}, Middleware: serpent.Chain( serpent.RequireNArgs(0), ), Handler: func(inv *serpent.Invocation) error { ctx := inv.Context() client, err := r.InitClient(inv) if err != nil { return err } org, err := orgContext.Selected(inv, client) if err != nil { return xerrors.Errorf("current organization: %w", err) } keys, err := client.ListProvisionerKeys(ctx, org.ID) if err != nil { return xerrors.Errorf("list provisioner keys: %w", err) } out, err := formatter.Format(inv.Context(), keys) if err != nil { return xerrors.Errorf("display provisioner keys: %w", err) } if out == "" { cliui.Infof(inv.Stderr, "No provisioner keys found.") return nil } _, _ = fmt.Fprintln(inv.Stdout, out) return nil }, } orgContext.AttachOptions(cmd) formatter.AttachOptions(&cmd.Options) return cmd } func (r *RootCmd) provisionerKeysDelete() *serpent.Command { orgContext := agpl.NewOrganizationContext() cmd := &serpent.Command{ Use: "delete ", Short: "Delete a provisioner key", Middleware: serpent.Chain( serpent.RequireNArgs(1), ), Handler: func(inv *serpent.Invocation) error { ctx := inv.Context() client, err := r.InitClient(inv) if err != nil { return err } org, err := orgContext.Selected(inv, client) if err != nil { return xerrors.Errorf("current organization: %w", err) } _, err = cliui.Prompt(inv, cliui.PromptOptions{ Text: fmt.Sprintf("Are you sure you want to delete provisioner key %s?", pretty.Sprint(cliui.DefaultStyles.Keyword, inv.Args[0])), IsConfirm: true, }) if err != nil { return err } err = client.DeleteProvisionerKey(ctx, org.ID, inv.Args[0]) if err != nil { return xerrors.Errorf("delete provisioner key: %w", err) } _, _ = fmt.Fprintf(inv.Stdout, "Successfully deleted provisioner key %s!\n", pretty.Sprint(cliui.DefaultStyles.Keyword, strings.ToLower(inv.Args[0]))) return nil }, } cmd.Options = serpent.OptionSet{ cliui.SkipPromptOption(), } orgContext.AttachOptions(cmd) return cmd }