diff --git a/config/interpolate_funcs.go b/config/interpolate_funcs.go index e912493b6..f73df85e6 100644 --- a/config/interpolate_funcs.go +++ b/config/interpolate_funcs.go @@ -69,6 +69,7 @@ func Funcs() map[string]ast.Function { "join": interpolationFuncJoin(), "jsonencode": interpolationFuncJSONEncode(), "length": interpolationFuncLength(), + "list": interpolationFuncList(), "lower": interpolationFuncLower(), "md5": interpolationFuncMd5(), "uuid": interpolationFuncUUID(), @@ -83,6 +84,26 @@ func Funcs() map[string]ast.Function { } } +// interpolationFuncList creates a list from the parameters passed +// to it. +func interpolationFuncList() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{}, + ReturnType: ast.TypeList, + Variadic: true, + VariadicType: ast.TypeString, + Callback: func(args []interface{}) (interface{}, error) { + var outputList []string + + for _, val := range args { + outputList = append(outputList, val.(string)) + } + + return stringSliceToVariableValue(outputList), nil + }, + } +} + // interpolationFuncCompact strips a list of multi-variable values // (e.g. as returned by "split") of any empty strings. func interpolationFuncCompact() ast.Function { diff --git a/config/interpolate_funcs_test.go b/config/interpolate_funcs_test.go index 46a6eba75..7ee10372f 100644 --- a/config/interpolate_funcs_test.go +++ b/config/interpolate_funcs_test.go @@ -12,6 +12,55 @@ import ( "github.com/hashicorp/hil/ast" ) +func TestInterpolateFuncList(t *testing.T) { + testFunction(t, testFunctionConfig{ + Cases: []testFunctionCase{ + // empty input returns empty list + { + `${list()}`, + []interface{}{}, + false, + }, + + // single input returns list of length 1 + { + `${list("hello")}`, + []interface{}{"hello"}, + false, + }, + + // two inputs returns list of length 2 + { + `${list("hello", "world")}`, + []interface{}{"hello", "world"}, + false, + }, + + // not a string input gives error + { + `${list("hello", "${var.list}")}`, + nil, + true, + }, + }, + Vars: map[string]ast.Variable{ + "var.list": { + Type: ast.TypeList, + Value: []ast.Variable{ + { + Type: ast.TypeString, + Value: "Hello", + }, + { + Type: ast.TypeString, + Value: "World", + }, + }, + }, + }, + }) +} + func TestInterpolateFuncCompact(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 c765e2d60..b2f66efd2 100644 --- a/website/source/docs/configuration/interpolation.html.md +++ b/website/source/docs/configuration/interpolation.html.md @@ -168,6 +168,11 @@ The supported built-in functions are: * `${length(split(",", "a,b,c"))}` = 3 * `${length("a,b,c")}` = 5 + * `list(items...)` - Returns a list consisting of the arguments to the function. + This function provides a way of representing list literals in interpolation. + * `${list("a", "b", "c")}` returns a list of `"a", "b", "c"`. + * `${list()}` returns an empty list. + * `lookup(map, key [, default])` - Performs a dynamic lookup into a mapping variable. The `map` parameter should be another variable, such as `var.amis`. If `key` does not exist in `map`, the interpolation will