Add TypeKVPairs field type (#3535)

This commit is contained in:
Chris Hoffman 2017-11-07 11:11:49 -05:00 committed by GitHub
parent 2b8d8f77d2
commit fe52ce1115
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 101 additions and 2 deletions

View File

@ -614,6 +614,8 @@ func (t FieldType) Zero() interface{} {
return false
case TypeMap:
return map[string]interface{}{}
case TypeKVPairs:
return map[string]string{}
case TypeDurationSecond:
return 0
case TypeSlice:

View File

@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"regexp"
"strings"
"github.com/hashicorp/vault/helper/parseutil"
"github.com/hashicorp/vault/helper/strutil"
@ -34,7 +35,8 @@ func (d *FieldData) Validate() error {
switch schema.Type {
case TypeBool, TypeInt, TypeMap, TypeDurationSecond, TypeString,
TypeNameString, TypeSlice, TypeStringSlice, TypeCommaStringSlice:
TypeNameString, TypeSlice, TypeStringSlice, TypeCommaStringSlice,
TypeKVPairs:
_, _, err := d.getPrimitive(field, schema)
if err != nil {
return fmt.Errorf("Error converting input %v for field %s: %s", value, field, err)
@ -110,7 +112,8 @@ func (d *FieldData) GetOkErr(k string) (interface{}, bool, error) {
switch schema.Type {
case TypeBool, TypeInt, TypeMap, TypeDurationSecond, TypeString,
TypeNameString, TypeSlice, TypeStringSlice, TypeCommaStringSlice:
TypeNameString, TypeSlice, TypeStringSlice, TypeCommaStringSlice,
TypeKVPairs:
return d.getPrimitive(k, schema)
default:
return nil, false,
@ -236,6 +239,29 @@ func (d *FieldData) getPrimitive(
}
return strutil.TrimStrings(result), true, nil
case TypeKVPairs:
// First try to parse this as a map
var mapResult map[string]string
if err := mapstructure.WeakDecode(raw, &mapResult); err == nil {
return mapResult, true, nil
}
// If map parse fails, parse as a string list of = delimited pairs
var listResult []string
if err := mapstructure.WeakDecode(raw, &listResult); err != nil {
return nil, true, err
}
result := make(map[string]string, len(listResult))
for _, keyPair := range listResult {
keyPairSlice := strings.SplitN(keyPair, "=", 2)
if len(keyPairSlice) != 2 || keyPairSlice[0] == "" {
return nil, false, fmt.Errorf("invalid key pair %q", keyPair)
}
result[keyPairSlice[0]] = keyPairSlice[1]
}
return result, true, nil
default:
panic(fmt.Sprintf("Unknown type: %s", schema.Type))
}

View File

@ -279,6 +279,53 @@ func TestFieldDataGet(t *testing.T) {
"bar.baz-bay123",
},
"keypair type, valid value map type": {
map[string]*FieldSchema{
"foo": &FieldSchema{Type: TypeKVPairs},
},
map[string]interface{}{
"foo": map[string]interface{}{
"key1": "value1",
"key2": "value2",
"key3": 1,
},
},
"foo",
map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "1",
},
},
"keypair type, list of equal sign delim key pairs type": {
map[string]*FieldSchema{
"foo": &FieldSchema{Type: TypeKVPairs},
},
map[string]interface{}{
"foo": []interface{}{"key1=value1", "key2=value2", "key3=1"},
},
"foo",
map[string]string{
"key1": "value1",
"key2": "value2",
"key3": "1",
},
},
"keypair type, single equal sign delim value": {
map[string]*FieldSchema{
"foo": &FieldSchema{Type: TypeKVPairs},
},
map[string]interface{}{
"foo": "key1=value1",
},
"foo",
map[string]string{
"key1": "value1",
},
},
"name string type, not supplied": {
map[string]*FieldSchema{
"foo": {Type: TypeNameString},
@ -359,6 +406,15 @@ func TestFieldDataGet(t *testing.T) {
"foo",
[]string{},
},
"type kv pair, not supplied": {
map[string]*FieldSchema{
"foo": {Type: TypeKVPairs},
},
map[string]interface{}{},
"foo",
map[string]string{},
},
}
for name, tc := range cases {
@ -422,6 +478,15 @@ func TestFieldDataGet_Error(t *testing.T) {
},
"foo",
},
"keypair type, csv version empty key name": {
map[string]*FieldSchema{
"foo": &FieldSchema{Type: TypeKVPairs},
},
map[string]interface{}{
"foo": []interface{}{"=value1", "key2=value2", "key3=1"},
},
"foo",
},
}
for _, tc := range cases {

View File

@ -30,6 +30,10 @@ const (
// rules. These rules include start and end with an alphanumeric
// character and characters in the middle can be alphanumeric or . or -.
TypeNameString
// TypeKVPairs allows you to represent the data as a map or a list of
// equal sign delimited key pairs
TypeKVPairs
)
func (t FieldType) String() string {
@ -44,6 +48,8 @@ func (t FieldType) String() string {
return "bool"
case TypeMap:
return "map"
case TypeKVPairs:
return "keypair"
case TypeDurationSecond:
return "duration (sec)"
case TypeSlice, TypeStringSlice, TypeCommaStringSlice: