From eec334c3d27c2edb6ad8744e3bdc046567ede5f7 Mon Sep 17 00:00:00 2001
From: Jeff Mitchell <jeff@hashicorp.com>
Date: Mon, 23 Apr 2018 15:29:23 -0400
Subject: [PATCH] Enable `-field` in `vault kv get/put` (#4426)

* Enable `-field` in `vault kv get/put`

Fixes #4424

* Unify nil value handling

* Use preflight helper
---
 command/kv_get.go | 14 ++++++++++++--
 command/kv_put.go |  6 +++++-
 command/util.go   | 17 ++++++++++++-----
 3 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/command/kv_get.go b/command/kv_get.go
index aa42e6cc0106..c66e36fdab59 100644
--- a/command/kv_get.go
+++ b/command/kv_get.go
@@ -43,7 +43,7 @@ Usage: vault kv get [options] KEY
 }
 
 func (c *KVGetCommand) Flags() *FlagSets {
-	set := c.flagSet(FlagSetHTTP | FlagSetOutputFormat)
+	set := c.flagSet(FlagSetHTTP | FlagSetOutputField | FlagSetOutputFormat)
 
 	// Common Options
 	f := set.NewFlagSet("Common Options")
@@ -124,7 +124,17 @@ func (c *KVGetCommand) Run(args []string) int {
 	}
 
 	if c.flagField != "" {
-		return PrintRawField(c.UI, secret, c.flagField)
+		if v2 {
+			// This is a v2, pass in the data field
+			if data, ok := secret.Data["data"]; ok && data != nil {
+				return PrintRawField(c.UI, data, c.flagField)
+			} else {
+				c.UI.Error(fmt.Sprintf("No data found at %s", path))
+				return 2
+			}
+		} else {
+			return PrintRawField(c.UI, secret, c.flagField)
+		}
 	}
 
 	// If we have wrap info print the secret normally.
diff --git a/command/kv_put.go b/command/kv_put.go
index e42b79dca749..56fac3e0761c 100644
--- a/command/kv_put.go
+++ b/command/kv_put.go
@@ -55,7 +55,7 @@ Usage: vault kv put [options] KEY [DATA]
 }
 
 func (c *KVPutCommand) Flags() *FlagSets {
-	set := c.flagSet(FlagSetHTTP | FlagSetOutputFormat)
+	set := c.flagSet(FlagSetHTTP | FlagSetOutputField | FlagSetOutputFormat)
 
 	// Common Options
 	f := set.NewFlagSet("Common Options")
@@ -152,5 +152,9 @@ func (c *KVPutCommand) Run(args []string) int {
 		return 0
 	}
 
+	if c.flagField != "" {
+		return PrintRawField(c.UI, secret, c.flagField)
+	}
+
 	return OutputSecret(c.UI, secret)
 }
diff --git a/command/util.go b/command/util.go
index b418ce7fc8ec..d9718ffc8746 100644
--- a/command/util.go
+++ b/command/util.go
@@ -20,7 +20,7 @@ func DefaultTokenHelper() (token.TokenHelper, error) {
 
 // RawField extracts the raw field from the given data and returns it as a
 // string for printing purposes.
-func RawField(secret *api.Secret, field string) (interface{}, bool) {
+func RawField(secret *api.Secret, field string) interface{} {
 	var val interface{}
 	switch {
 	case secret.Auth != nil:
@@ -72,13 +72,20 @@ func RawField(secret *api.Secret, field string) (interface{}, bool) {
 		}
 	}
 
-	return val, val != nil
+	return val
 }
 
 // PrintRawField prints raw field from the secret.
-func PrintRawField(ui cli.Ui, secret *api.Secret, field string) int {
-	val, ok := RawField(secret, field)
-	if !ok {
+func PrintRawField(ui cli.Ui, data interface{}, field string) int {
+	var val interface{}
+	switch data.(type) {
+	case *api.Secret:
+		val = RawField(data.(*api.Secret), field)
+	case map[string]interface{}:
+		val = data.(map[string]interface{})[field]
+	}
+
+	if val == nil {
 		ui.Error(fmt.Sprintf("Field %q not present in secret", field))
 		return 1
 	}