diff --git a/api/secret.go b/api/secret.go index 6dfacc0031..774a0e6e90 100644 --- a/api/secret.go +++ b/api/secret.go @@ -3,49 +3,25 @@ package api import ( "encoding/json" "io" - "strings" - - "github.com/mitchellh/mapstructure" ) // Secret is the structure returned for every secret within Vault. type Secret struct { - VaultId string `mapstructure:"vault_id"` + VaultId string `json:"vault_id"` Renewable bool - LeaseDuration int `mapstructure:"lease_duration"` - LeaseDurationMax int `mapstructure:"lease_duration_max"` - Data map[string]interface{} `mapstructure:"data"` + LeaseDuration int `json:"lease_duration"` + LeaseDurationMax int `json:"lease_duration_max"` + Data map[string]interface{} `json:"data"` } // ParseSecret is used to parse a secret value from JSON from an io.Reader. func ParseSecret(r io.Reader) (*Secret, error) { // First decode the JSON into a map[string]interface{} - var raw map[string]interface{} + var secret Secret dec := json.NewDecoder(r) - if err := dec.Decode(&raw); err != nil { + if err := dec.Decode(&secret); err != nil { return nil, err } - // Use mapstructure to get as much as possible - var result Secret - var metadata mapstructure.Metadata - mdec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ - Metadata: &metadata, - Result: &result, - }) - if err != nil { - return nil, err - } - if err := mdec.Decode(raw); err != nil { - return nil, err - } - - // Delete the keys we decoded from the raw value, then set that - // raw value as the resulting data. - for _, k := range metadata.Keys { - delete(raw, strings.ToLower(k)) - } - - result.Data = raw - return &result, nil + return &secret, nil } diff --git a/command/get.go b/command/read.go similarity index 79% rename from command/get.go rename to command/read.go index 3f48e93705..64800e530e 100644 --- a/command/get.go +++ b/command/read.go @@ -4,13 +4,13 @@ import ( "strings" ) -// GetCommand is a Command that gets data from the Vault. -type GetCommand struct { +// ReadCommand is a Command that gets data from the Vault. +type ReadCommand struct { Meta } -func (c *GetCommand) Run(args []string) int { - flags := c.Meta.FlagSet("put", FlagSetDefault) +func (c *ReadCommand) Run(args []string) int { + flags := c.Meta.FlagSet("read", FlagSetDefault) flags.Usage = func() { c.Ui.Error(c.Help()) } if err := flags.Parse(args); err != nil { return 1 @@ -19,11 +19,11 @@ func (c *GetCommand) Run(args []string) int { return 0 } -func (c *GetCommand) Synopsis() string { - return "Get data or secrets from Vault" +func (c *ReadCommand) Synopsis() string { + return "Read data or secrets from Vault" } -func (c *GetCommand) Help() string { +func (c *ReadCommand) Help() string { helpText := ` Usage: vault get [options] path diff --git a/command/put.go b/command/write.go similarity index 50% rename from command/put.go rename to command/write.go index c41d8a3a7f..f17244ad85 100644 --- a/command/put.go +++ b/command/write.go @@ -1,35 +1,66 @@ package command import ( + "fmt" "strings" ) -// PutCommand is a Command that puts data into the Vault. -type PutCommand struct { +// DefaultDataKey is the key used in the write as a default for data. +const DefaultDataKey = "value" + +// WriteCommand is a Command that puts data into the Vault. +type WriteCommand struct { Meta } -func (c *PutCommand) Run(args []string) int { - flags := c.Meta.FlagSet("put", FlagSetDefault) +func (c *WriteCommand) Run(args []string) int { + flags := c.Meta.FlagSet("write", FlagSetDefault) flags.Usage = func() { c.Ui.Error(c.Help()) } if err := flags.Parse(args); err != nil { return 1 } + args = flags.Args() + if len(args) != 2 { + c.Ui.Error("write expects two arguments") + flags.Usage() + return 1 + } + + path := args[0] + if path[0] == '/' { + path = path[1:] + } + data := map[string]interface{}{DefaultDataKey: args[1]} + + client, err := c.Client() + if err != nil { + c.Ui.Error(fmt.Sprintf( + "Error initializing client: %s", err)) + return 2 + } + + if err := client.Logical().Write(path, data); err != nil { + c.Ui.Error(fmt.Sprintf( + "Error writing data to %s: %s", path, err)) + return 1 + } + + c.Ui.Output(fmt.Sprintf("Success! Data written to: %s", path)) return 0 } -func (c *PutCommand) Synopsis() string { - return "Put secrets or configuration into Vault" +func (c *WriteCommand) Synopsis() string { + return "Write secrets or configuration into Vault" } -func (c *PutCommand) Help() string { +func (c *WriteCommand) Help() string { helpText := ` -Usage: vault put [options] path data +Usage: vault write [options] path data Write data (secrets or configuration) into Vault. - Put sends data into Vault at the given path. The behavior of the write + Write sends data into Vault at the given path. The behavior of the write is determined by the backend at the given path. For example, writing to "aws/policy/ops" will create an "ops" IAM policy for the AWS backend (configuration), but writing to "consul/foo" will write a value directly @@ -37,7 +68,10 @@ Usage: vault put [options] path data you're using for more information on key structure. If data is "-" then the data will be ready from stdin. To write a literal - "-", you'll have to pipe that value in from stdin. + "-", you'll have to pipe that value in from stdin. To write data from a + file, pipe the file contents in via stdin and set data to "-". + + If data is a string, it will be sent with the key of "value". General Options: diff --git a/command/write_test.go b/command/write_test.go new file mode 100644 index 0000000000..355e8d4a50 --- /dev/null +++ b/command/write_test.go @@ -0,0 +1,45 @@ +package command + +import ( + "testing" + + "github.com/hashicorp/vault/http" + "github.com/hashicorp/vault/vault" + "github.com/mitchellh/cli" +) + +func TestWrite(t *testing.T) { + core, _ := vault.TestCoreUnsealed(t) + ln, addr := http.TestServer(t, core) + defer ln.Close() + + ui := new(cli.MockUi) + c := &WriteCommand{ + Meta: Meta{ + Ui: ui, + }, + } + + args := []string{ + "-address", addr, + "secret/foo", + "bar", + } + if code := c.Run(args); code != 0 { + t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) + } + + client, err := c.Client() + if err != nil { + t.Fatalf("err: %s", err) + } + + resp, err := client.Logical().Read("secret/foo") + if err != nil { + t.Fatalf("err: %s", err) + } + + if resp.Data[DefaultDataKey] != "bar" { + t.Fatalf("bad: %#v", resp) + } +} diff --git a/commands.go b/commands.go index 34d7132f29..ebaf2689ec 100644 --- a/commands.go +++ b/commands.go @@ -24,14 +24,14 @@ func init() { }, nil }, - "get": func() (cli.Command, error) { - return &command.GetCommand{ + "read": func() (cli.Command, error) { + return &command.ReadCommand{ Meta: meta, }, nil }, - "put": func() (cli.Command, error) { - return &command.PutCommand{ + "write": func() (cli.Command, error) { + return &command.WriteCommand{ Meta: meta, }, nil },