command/write

This commit is contained in:
Mitchell Hashimoto
2015-03-15 20:35:33 -07:00
parent 80798a3869
commit 8093f94c65
5 changed files with 107 additions and 52 deletions

View File

@@ -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
}

View File

@@ -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

View File

@@ -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:

45
command/write_test.go Normal file
View File

@@ -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)
}
}

View File

@@ -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
},