Lokasi ngalangkungan proxy:   [ UP ]  
[Ngawartoskeun bug]   [Panyetelan cookie]                
Skip to content

Commit 594ea10

Browse files
committed
config: support lists and maps in jsonencode
For now we only support lists and maps whose values are strings, not deeply nested data.
1 parent eedc523 commit 594ea10

3 files changed

Lines changed: 93 additions & 7 deletions

File tree

config/interpolate_funcs.go

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -409,16 +409,54 @@ func interpolationFuncJoin() ast.Function {
409409
}
410410

411411
// interpolationFuncJSONEncode implements the "jsonencode" function that encodes
412-
// a string as its JSON representation.
412+
// a string, list, or map as its JSON representation. For now, values in the
413+
// list or map may only be strings.
413414
func interpolationFuncJSONEncode() ast.Function {
414415
return ast.Function{
415-
ArgTypes: []ast.Type{ast.TypeString},
416+
ArgTypes: []ast.Type{ast.TypeAny},
416417
ReturnType: ast.TypeString,
417418
Callback: func(args []interface{}) (interface{}, error) {
418-
s := args[0].(string)
419-
jEnc, err := json.Marshal(s)
419+
var toEncode interface{}
420+
421+
switch typedArg := args[0].(type) {
422+
case string:
423+
toEncode = typedArg
424+
425+
case []ast.Variable:
426+
// We preallocate the list here. Note that it's important that in
427+
// the length 0 case, we have an empty list rather than nil, as
428+
// they encode differently.
429+
// XXX It would be nice to support arbitrarily nested data here. Is
430+
// there an inverse of hil.InterfaceToVariable?
431+
strings := make([]string, len(typedArg))
432+
433+
for i, v := range typedArg {
434+
if v.Type != ast.TypeString {
435+
return "", fmt.Errorf("list elements must be strings")
436+
}
437+
strings[i] = v.Value.(string)
438+
}
439+
toEncode = strings
440+
441+
case map[string]ast.Variable:
442+
// XXX It would be nice to support arbitrarily nested data here. Is
443+
// there an inverse of hil.InterfaceToVariable?
444+
stringMap := make(map[string]string)
445+
for k, v := range typedArg {
446+
if v.Type != ast.TypeString {
447+
return "", fmt.Errorf("map values must be strings")
448+
}
449+
stringMap[k] = v.Value.(string)
450+
}
451+
toEncode = stringMap
452+
453+
default:
454+
return "", fmt.Errorf("unknown type for JSON encoding: %T", args[0])
455+
}
456+
457+
jEnc, err := json.Marshal(toEncode)
420458
if err != nil {
421-
return "", fmt.Errorf("failed to encode JSON data '%s'", s)
459+
return "", fmt.Errorf("failed to encode JSON data '%s'", toEncode)
422460
}
423461
return string(jEnc), nil
424462
},

config/interpolate_funcs_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,22 @@ func TestInterpolateFuncJSONEncode(t *testing.T) {
419419
Value: " foo \\ \n \t \" bar ",
420420
Type: ast.TypeString,
421421
},
422+
"list": interfaceToVariableSwallowError([]string{"foo", "bar\tbaz"}),
423+
// XXX can't use InterfaceToVariable as it converts empty slice into empty
424+
// map.
425+
"emptylist": ast.Variable{
426+
Value: []ast.Variable{},
427+
Type: ast.TypeList,
428+
},
429+
"map": interfaceToVariableSwallowError(map[string]string{
430+
"foo": "bar",
431+
"ba \n z": "q\\x",
432+
}),
433+
"emptymap": interfaceToVariableSwallowError(map[string]string{}),
434+
435+
// Not yet supported (but it would be nice)
436+
"nestedlist": interfaceToVariableSwallowError([][]string{{"foo"}}),
437+
"nestedmap": interfaceToVariableSwallowError(map[string][]string{"foo": {"bar"}}),
422438
},
423439
Cases: []testFunctionCase{
424440
{
@@ -446,6 +462,36 @@ func TestInterpolateFuncJSONEncode(t *testing.T) {
446462
nil,
447463
true,
448464
},
465+
{
466+
`${jsonencode(list)}`,
467+
`["foo","bar\tbaz"]`,
468+
false,
469+
},
470+
{
471+
`${jsonencode(emptylist)}`,
472+
`[]`,
473+
false,
474+
},
475+
{
476+
`${jsonencode(map)}`,
477+
`{"ba \n z":"q\\x","foo":"bar"}`,
478+
false,
479+
},
480+
{
481+
`${jsonencode(emptymap)}`,
482+
`{}`,
483+
false,
484+
},
485+
{
486+
`${jsonencode(nestedlist)}`,
487+
nil,
488+
true,
489+
},
490+
{
491+
`${jsonencode(nestedmap)}`,
492+
nil,
493+
true,
494+
},
449495
},
450496
})
451497
}

website/source/docs/configuration/interpolation.html.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,10 @@ The supported built-in functions are:
150150
only possible with splat variables from resources with a count
151151
greater than one. Example: `join(",", aws_instance.foo.*.id)`
152152

153-
* `jsonencode(string)` - Returns a JSON-encoded representation of the given
154-
string (including double quotes).
153+
* `jsonencode(item)` - Returns a JSON-encoded representation of the given
154+
item, which may be a string, list of strings, or map from string to string.
155+
Note that if the item is a string, the return value includes the double
156+
quotes.
155157

156158
* `length(list)` - Returns a number of members in a given list
157159
or a number of characters in a given string.

0 commit comments

Comments
 (0)