1package command
2
3import (
4	"fmt"
5	"io"
6	"os"
7	"strings"
8
9	"github.com/mitchellh/cli"
10	"github.com/posener/complete"
11)
12
13var (
14	_ cli.Command             = (*DeleteCommand)(nil)
15	_ cli.CommandAutocomplete = (*DeleteCommand)(nil)
16)
17
18type DeleteCommand struct {
19	*BaseCommand
20
21	testStdin io.Reader // for tests
22}
23
24func (c *DeleteCommand) Synopsis() string {
25	return "Delete secrets and configuration"
26}
27
28func (c *DeleteCommand) Help() string {
29	helpText := `
30Usage: vault delete [options] PATH
31
32  Deletes secrets and configuration from Vault at the given path. The behavior
33  of "delete" is delegated to the backend corresponding to the given path.
34
35  Remove data in the status secret backend:
36
37      $ vault delete secret/my-secret
38
39  Uninstall an encryption key in the transit backend:
40
41      $ vault delete transit/keys/my-key
42
43  Delete an IAM role:
44
45      $ vault delete aws/roles/ops
46
47  For a full list of examples and paths, please see the documentation that
48  corresponds to the secret backend in use.
49
50` + c.Flags().Help()
51
52	return strings.TrimSpace(helpText)
53}
54
55func (c *DeleteCommand) Flags() *FlagSets {
56	return c.flagSet(FlagSetHTTP | FlagSetOutputField | FlagSetOutputFormat)
57}
58
59func (c *DeleteCommand) AutocompleteArgs() complete.Predictor {
60	return c.PredictVaultFiles()
61}
62
63func (c *DeleteCommand) AutocompleteFlags() complete.Flags {
64	return c.Flags().Completions()
65}
66
67func (c *DeleteCommand) Run(args []string) int {
68	f := c.Flags()
69
70	if err := f.Parse(args); err != nil {
71		c.UI.Error(err.Error())
72		return 1
73	}
74
75	args = f.Args()
76	switch {
77	case len(args) < 1:
78		c.UI.Error(fmt.Sprintf("Not enough arguments (expected at least 1, got %d)", len(args)))
79		return 1
80	}
81
82	client, err := c.Client()
83	if err != nil {
84		c.UI.Error(err.Error())
85		return 2
86	}
87
88	// Pull our fake stdin if needed
89	stdin := (io.Reader)(os.Stdin)
90	if c.testStdin != nil {
91		stdin = c.testStdin
92	}
93
94	path := sanitizePath(args[0])
95
96	data, err := parseArgsDataStringLists(stdin, args[1:])
97	if err != nil {
98		c.UI.Error(fmt.Sprintf("Failed to parse string list data: %s", err))
99		return 1
100	}
101
102	secret, err := client.Logical().DeleteWithData(path, data)
103	if err != nil {
104		c.UI.Error(fmt.Sprintf("Error deleting %s: %s", path, err))
105		if secret != nil {
106			OutputSecret(c.UI, secret)
107		}
108		return 2
109	}
110
111	if secret == nil {
112		// Don't output anything unless using the "table" format
113		if Format(c.UI) == "table" {
114			c.UI.Info(fmt.Sprintf("Success! Data deleted (if it existed) at: %s", path))
115		}
116		return 0
117	}
118
119	// Handle single field output
120	if c.flagField != "" {
121		return PrintRawField(c.UI, secret, c.flagField)
122	}
123
124	return OutputSecret(c.UI, secret)
125}
126