diff --git a/config/interpolate_funcs.go b/config/interpolate_funcs.go index 8a04e9316..9f929e106 100644 --- a/config/interpolate_funcs.go +++ b/config/interpolate_funcs.go @@ -7,6 +7,7 @@ import ( "crypto/sha256" "encoding/base64" "encoding/hex" + "encoding/json" "errors" "fmt" "io/ioutil" @@ -40,6 +41,7 @@ func Funcs() map[string]ast.Function { "formatlist": interpolationFuncFormatList(), "index": interpolationFuncIndex(), "join": interpolationFuncJoin(), + "jsonencode": interpolationFuncJSONEncode(), "length": interpolationFuncLength(), "lower": interpolationFuncLower(), "md5": interpolationFuncMd5(), @@ -364,6 +366,23 @@ func interpolationFuncJoin() ast.Function { } } +// interpolationFuncJSONEncode implements the "jsonencode" function that encodes +// a string as its JSON representation. +func interpolationFuncJSONEncode() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{ast.TypeString}, + ReturnType: ast.TypeString, + Callback: func(args []interface{}) (interface{}, error) { + s := args[0].(string) + jEnc, err := json.Marshal(s) + if err != nil { + return "", fmt.Errorf("failed to encode JSON data '%s'", s) + } + return string(jEnc), nil + }, + } +} + // interpolationFuncReplace implements the "replace" function that does // string replacement. func interpolationFuncReplace() ast.Function { diff --git a/config/interpolate_funcs_test.go b/config/interpolate_funcs_test.go index 55b435933..123ee39f3 100644 --- a/config/interpolate_funcs_test.go +++ b/config/interpolate_funcs_test.go @@ -437,6 +437,48 @@ func TestInterpolateFuncJoin(t *testing.T) { }) } +func TestInterpolateFuncJSONEncode(t *testing.T) { + testFunction(t, testFunctionConfig{ + Vars: map[string]ast.Variable{ + "easy": ast.Variable{ + Value: "test", + Type: ast.TypeString, + }, + "hard": ast.Variable{ + Value: " foo \\ \n \t \" bar ", + Type: ast.TypeString, + }, + }, + Cases: []testFunctionCase{ + { + `${jsonencode("test")}`, + `"test"`, + false, + }, + { + `${jsonencode(easy)}`, + `"test"`, + false, + }, + { + `${jsonencode(hard)}`, + `" foo \\ \n \t \" bar "`, + false, + }, + { + `${jsonencode("")}`, + `""`, + false, + }, + { + `${jsonencode()}`, + nil, + true, + }, + }, + }) +} + func TestInterpolateFuncReplace(t *testing.T) { testFunction(t, testFunctionConfig{ Cases: []testFunctionCase{ diff --git a/website/source/docs/configuration/interpolation.html.md b/website/source/docs/configuration/interpolation.html.md index c1be98548..1d5674e08 100644 --- a/website/source/docs/configuration/interpolation.html.md +++ b/website/source/docs/configuration/interpolation.html.md @@ -150,6 +150,9 @@ The supported built-in functions are: only possible with splat variables from resources with a count greater than one. Example: `join(",", aws_instance.foo.*.id)` + * `jsonencode(string)` - Returns a JSON-encoded representation of the given + string (including double quotes). + * `length(list)` - Returns a number of members in a given list or a number of characters in a given string. * `${length(split(",", "a,b,c"))}` = 3