2014-07-21 20:24:44 +02:00
|
|
|
package config
|
|
|
|
|
|
|
|
import (
|
2014-07-23 03:29:45 +02:00
|
|
|
"fmt"
|
2014-07-21 20:24:44 +02:00
|
|
|
"reflect"
|
2014-07-21 20:30:43 +02:00
|
|
|
"strings"
|
2014-07-21 20:24:44 +02:00
|
|
|
|
2016-01-31 08:38:37 +01:00
|
|
|
"github.com/hashicorp/hil"
|
|
|
|
"github.com/hashicorp/hil/ast"
|
2014-07-21 20:24:44 +02:00
|
|
|
"github.com/mitchellh/reflectwalk"
|
|
|
|
)
|
|
|
|
|
|
|
|
// interpolationWalker implements interfaces for the reflectwalk package
|
|
|
|
// (github.com/mitchellh/reflectwalk) that can be used to automatically
|
|
|
|
// execute a callback for an interpolation.
|
|
|
|
type interpolationWalker struct {
|
2014-10-10 06:15:08 +02:00
|
|
|
// F is the function to call for every interpolation. It can be nil.
|
|
|
|
//
|
|
|
|
// If Replace is true, then the return value of F will be used to
|
|
|
|
// replace the interpolation.
|
2014-10-10 23:50:35 +02:00
|
|
|
F interpolationWalkerFunc
|
|
|
|
Replace bool
|
2014-10-10 06:15:08 +02:00
|
|
|
|
|
|
|
// ContextF is an advanced version of F that also receives the
|
|
|
|
// location of where it is in the structure. This lets you do
|
|
|
|
// context-aware validation.
|
|
|
|
ContextF interpolationWalkerContextFunc
|
2014-07-21 20:24:44 +02:00
|
|
|
|
2014-07-21 20:45:56 +02:00
|
|
|
key []string
|
2014-08-27 22:29:02 +02:00
|
|
|
lastValue reflect.Value
|
2014-07-21 20:45:56 +02:00
|
|
|
loc reflectwalk.Location
|
|
|
|
cs []reflect.Value
|
2014-10-10 00:55:22 +02:00
|
|
|
csKey []reflect.Value
|
2014-07-21 20:45:56 +02:00
|
|
|
csData interface{}
|
2014-10-10 00:55:22 +02:00
|
|
|
sliceIndex int
|
2014-07-21 20:45:56 +02:00
|
|
|
unknownKeys []string
|
2014-07-21 20:24:44 +02:00
|
|
|
}
|
|
|
|
|
2014-07-21 20:30:43 +02:00
|
|
|
// interpolationWalkerFunc is the callback called by interpolationWalk.
|
|
|
|
// It is called with any interpolation found. It should return a value
|
|
|
|
// to replace the interpolation with, along with any errors.
|
|
|
|
//
|
|
|
|
// If Replace is set to false in interpolationWalker, then the replace
|
|
|
|
// value can be anything as it will have no effect.
|
2016-04-11 19:40:06 +02:00
|
|
|
type interpolationWalkerFunc func(ast.Node) (interface{}, error)
|
2014-07-21 20:24:44 +02:00
|
|
|
|
2014-10-10 06:15:08 +02:00
|
|
|
// interpolationWalkerContextFunc is called by interpolationWalk if
|
|
|
|
// ContextF is set. This receives both the interpolation and the location
|
|
|
|
// where the interpolation is.
|
|
|
|
//
|
|
|
|
// This callback can be used to validate the location of the interpolation
|
|
|
|
// within the configuration.
|
2015-01-13 19:27:57 +01:00
|
|
|
type interpolationWalkerContextFunc func(reflectwalk.Location, ast.Node)
|
2014-10-10 06:15:08 +02:00
|
|
|
|
2014-07-21 20:24:44 +02:00
|
|
|
func (w *interpolationWalker) Enter(loc reflectwalk.Location) error {
|
|
|
|
w.loc = loc
|
2016-07-07 20:15:32 +02:00
|
|
|
if loc == reflectwalk.WalkLoc {
|
|
|
|
w.sliceIndex = -1
|
|
|
|
}
|
2014-07-21 20:24:44 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *interpolationWalker) Exit(loc reflectwalk.Location) error {
|
|
|
|
w.loc = reflectwalk.None
|
|
|
|
|
|
|
|
switch loc {
|
|
|
|
case reflectwalk.Map:
|
|
|
|
w.cs = w.cs[:len(w.cs)-1]
|
|
|
|
case reflectwalk.MapValue:
|
|
|
|
w.key = w.key[:len(w.key)-1]
|
2014-10-10 00:55:22 +02:00
|
|
|
w.csKey = w.csKey[:len(w.csKey)-1]
|
|
|
|
case reflectwalk.Slice:
|
|
|
|
// Split any values that need to be split
|
|
|
|
w.splitSlice()
|
|
|
|
w.cs = w.cs[:len(w.cs)-1]
|
|
|
|
case reflectwalk.SliceElem:
|
|
|
|
w.csKey = w.csKey[:len(w.csKey)-1]
|
2016-07-07 20:15:32 +02:00
|
|
|
w.sliceIndex = -1
|
2014-07-21 20:24:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *interpolationWalker) Map(m reflect.Value) error {
|
|
|
|
w.cs = append(w.cs, m)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *interpolationWalker) MapElem(m, k, v reflect.Value) error {
|
|
|
|
w.csData = k
|
2014-10-10 00:55:22 +02:00
|
|
|
w.csKey = append(w.csKey, k)
|
2016-07-07 20:15:32 +02:00
|
|
|
|
|
|
|
if w.sliceIndex != -1 {
|
|
|
|
w.key = append(w.key, fmt.Sprintf("%d.%s", w.sliceIndex, k.String()))
|
|
|
|
} else {
|
|
|
|
w.key = append(w.key, k.String())
|
|
|
|
}
|
|
|
|
|
2014-08-27 22:29:02 +02:00
|
|
|
w.lastValue = v
|
2014-07-21 20:24:44 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-10-10 00:55:22 +02:00
|
|
|
func (w *interpolationWalker) Slice(s reflect.Value) error {
|
|
|
|
w.cs = append(w.cs, s)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *interpolationWalker) SliceElem(i int, elem reflect.Value) error {
|
|
|
|
w.csKey = append(w.csKey, reflect.ValueOf(i))
|
|
|
|
w.sliceIndex = i
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-07-21 20:24:44 +02:00
|
|
|
func (w *interpolationWalker) Primitive(v reflect.Value) error {
|
2014-07-21 20:30:43 +02:00
|
|
|
setV := v
|
|
|
|
|
2014-07-21 20:24:44 +02:00
|
|
|
// We only care about strings
|
|
|
|
if v.Kind() == reflect.Interface {
|
2014-07-21 20:30:43 +02:00
|
|
|
setV = v
|
2014-07-21 20:24:44 +02:00
|
|
|
v = v.Elem()
|
|
|
|
}
|
|
|
|
if v.Kind() != reflect.String {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-01-31 08:38:37 +01:00
|
|
|
astRoot, err := hil.Parse(v.String())
|
2015-01-13 19:27:57 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2014-07-21 20:24:44 +02:00
|
|
|
|
2016-01-19 21:51:56 +01:00
|
|
|
// If the AST we got is just a literal string value with the same
|
|
|
|
// value then we ignore it. We have to check if its the same value
|
|
|
|
// because it is possible to input a string, get out a string, and
|
|
|
|
// have it be different. For example: "foo-$${bar}" turns into
|
|
|
|
// "foo-${bar}"
|
|
|
|
if n, ok := astRoot.(*ast.LiteralNode); ok {
|
|
|
|
if s, ok := n.Value.(string); ok && s == v.String() {
|
|
|
|
return nil
|
|
|
|
}
|
2014-07-21 20:24:44 +02:00
|
|
|
}
|
|
|
|
|
2015-01-13 19:27:57 +01:00
|
|
|
if w.ContextF != nil {
|
|
|
|
w.ContextF(w.loc, astRoot)
|
|
|
|
}
|
2014-10-10 06:15:08 +02:00
|
|
|
|
2015-01-13 19:27:57 +01:00
|
|
|
if w.F == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2014-10-10 06:15:08 +02:00
|
|
|
|
2015-01-13 19:27:57 +01:00
|
|
|
replaceVal, err := w.F(astRoot)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf(
|
|
|
|
"%s in:\n\n%s",
|
|
|
|
err, v.String())
|
|
|
|
}
|
2014-07-21 20:24:44 +02:00
|
|
|
|
2015-01-13 19:27:57 +01:00
|
|
|
if w.Replace {
|
|
|
|
// We need to determine if we need to remove this element
|
|
|
|
// if the result contains any "UnknownVariableValue" which is
|
|
|
|
// set if it is computed. This behavior is different if we're
|
|
|
|
// splitting (in a SliceElem) or not.
|
|
|
|
remove := false
|
core: support native list variables in config
This commit adds support for native list variables and outputs, building
up on the previous change to state. Interpolation functions now return
native lists in preference to StringList.
List variables are defined like this:
variable "test" {
# This can also be inferred
type = "list"
default = ["Hello", "World"]
}
output "test_out" {
value = "${var.a_list}"
}
This results in the following state:
```
...
"outputs": {
"test_out": [
"hello",
"world"
]
},
...
```
And the result of terraform output is as follows:
```
$ terraform output
test_out = [
hello
world
]
```
Using the output name, an xargs-friendly representation is output:
```
$ terraform output test_out
hello
world
```
The output command also supports indexing into the list (with
appropriate range checking and no wrapping):
```
$ terraform output test_out 1
world
```
Along with maps, list outputs from one module may be passed as variables
into another, removing the need for the `join(",", var.list_as_string)`
and `split(",", var.list_as_string)` which was previously necessary in
Terraform configuration.
This commit also updates the tests and implementations of built-in
interpolation functions to take and return native lists where
appropriate.
A backwards compatibility note: previously the concat interpolation
function was capable of concatenating either strings or lists. The
strings use case was deprectated a long time ago but still remained.
Because we cannot return `ast.TypeAny` from an interpolation function,
this use case is no longer supported for strings - `concat` is only
capable of concatenating lists. This should not be a huge issue - the
type checker picks up incorrect parameters, and the native HIL string
concatenation - or the `join` function - can be used to replicate the
missing behaviour.
2016-04-22 02:03:24 +02:00
|
|
|
if w.loc == reflectwalk.SliceElem {
|
|
|
|
switch typedReplaceVal := replaceVal.(type) {
|
|
|
|
case string:
|
|
|
|
if typedReplaceVal == UnknownVariableValue {
|
|
|
|
remove = true
|
|
|
|
}
|
|
|
|
case []interface{}:
|
|
|
|
if hasUnknownValue(typedReplaceVal) {
|
2015-01-13 19:27:57 +01:00
|
|
|
remove = true
|
2014-10-10 00:55:22 +02:00
|
|
|
}
|
|
|
|
}
|
2015-01-13 19:27:57 +01:00
|
|
|
} else if replaceVal == UnknownVariableValue {
|
|
|
|
remove = true
|
|
|
|
}
|
2016-07-07 20:15:32 +02:00
|
|
|
|
2015-01-13 19:27:57 +01:00
|
|
|
if remove {
|
2016-10-27 05:24:23 +02:00
|
|
|
w.unknownKeys = append(w.unknownKeys, strings.Join(w.key, "."))
|
2014-07-21 20:24:44 +02:00
|
|
|
}
|
|
|
|
|
2015-01-13 19:27:57 +01:00
|
|
|
resultVal := reflect.ValueOf(replaceVal)
|
2014-08-27 22:29:02 +02:00
|
|
|
switch w.loc {
|
|
|
|
case reflectwalk.MapKey:
|
|
|
|
m := w.cs[len(w.cs)-1]
|
|
|
|
|
|
|
|
// Delete the old value
|
|
|
|
var zero reflect.Value
|
|
|
|
m.SetMapIndex(w.csData.(reflect.Value), zero)
|
|
|
|
|
|
|
|
// Set the new key with the existing value
|
|
|
|
m.SetMapIndex(resultVal, w.lastValue)
|
|
|
|
|
|
|
|
// Set the key to be the new key
|
|
|
|
w.csData = resultVal
|
|
|
|
case reflectwalk.MapValue:
|
2014-07-21 20:30:43 +02:00
|
|
|
// If we're in a map, then the only way to set a map value is
|
|
|
|
// to set it directly.
|
|
|
|
m := w.cs[len(w.cs)-1]
|
|
|
|
mk := w.csData.(reflect.Value)
|
|
|
|
m.SetMapIndex(mk, resultVal)
|
2014-08-27 22:29:02 +02:00
|
|
|
default:
|
2014-07-21 20:30:43 +02:00
|
|
|
// Otherwise, we should be addressable
|
|
|
|
setV.Set(resultVal)
|
|
|
|
}
|
2014-07-21 20:24:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2014-07-21 20:45:56 +02:00
|
|
|
|
2014-10-10 01:12:30 +02:00
|
|
|
func (w *interpolationWalker) replaceCurrent(v reflect.Value) {
|
|
|
|
c := w.cs[len(w.cs)-2]
|
2014-10-10 00:55:22 +02:00
|
|
|
switch c.Kind() {
|
|
|
|
case reflect.Map:
|
|
|
|
// Get the key and delete it
|
|
|
|
k := w.csKey[len(w.csKey)-1]
|
|
|
|
c.SetMapIndex(k, v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
core: support native list variables in config
This commit adds support for native list variables and outputs, building
up on the previous change to state. Interpolation functions now return
native lists in preference to StringList.
List variables are defined like this:
variable "test" {
# This can also be inferred
type = "list"
default = ["Hello", "World"]
}
output "test_out" {
value = "${var.a_list}"
}
This results in the following state:
```
...
"outputs": {
"test_out": [
"hello",
"world"
]
},
...
```
And the result of terraform output is as follows:
```
$ terraform output
test_out = [
hello
world
]
```
Using the output name, an xargs-friendly representation is output:
```
$ terraform output test_out
hello
world
```
The output command also supports indexing into the list (with
appropriate range checking and no wrapping):
```
$ terraform output test_out 1
world
```
Along with maps, list outputs from one module may be passed as variables
into another, removing the need for the `join(",", var.list_as_string)`
and `split(",", var.list_as_string)` which was previously necessary in
Terraform configuration.
This commit also updates the tests and implementations of built-in
interpolation functions to take and return native lists where
appropriate.
A backwards compatibility note: previously the concat interpolation
function was capable of concatenating either strings or lists. The
strings use case was deprectated a long time ago but still remained.
Because we cannot return `ast.TypeAny` from an interpolation function,
this use case is no longer supported for strings - `concat` is only
capable of concatenating lists. This should not be a huge issue - the
type checker picks up incorrect parameters, and the native HIL string
concatenation - or the `join` function - can be used to replicate the
missing behaviour.
2016-04-22 02:03:24 +02:00
|
|
|
func hasUnknownValue(variable []interface{}) bool {
|
|
|
|
for _, value := range variable {
|
|
|
|
if strVal, ok := value.(string); ok {
|
|
|
|
if strVal == UnknownVariableValue {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2014-10-10 00:55:22 +02:00
|
|
|
func (w *interpolationWalker) splitSlice() {
|
|
|
|
raw := w.cs[len(w.cs)-1]
|
core: support native list variables in config
This commit adds support for native list variables and outputs, building
up on the previous change to state. Interpolation functions now return
native lists in preference to StringList.
List variables are defined like this:
variable "test" {
# This can also be inferred
type = "list"
default = ["Hello", "World"]
}
output "test_out" {
value = "${var.a_list}"
}
This results in the following state:
```
...
"outputs": {
"test_out": [
"hello",
"world"
]
},
...
```
And the result of terraform output is as follows:
```
$ terraform output
test_out = [
hello
world
]
```
Using the output name, an xargs-friendly representation is output:
```
$ terraform output test_out
hello
world
```
The output command also supports indexing into the list (with
appropriate range checking and no wrapping):
```
$ terraform output test_out 1
world
```
Along with maps, list outputs from one module may be passed as variables
into another, removing the need for the `join(",", var.list_as_string)`
and `split(",", var.list_as_string)` which was previously necessary in
Terraform configuration.
This commit also updates the tests and implementations of built-in
interpolation functions to take and return native lists where
appropriate.
A backwards compatibility note: previously the concat interpolation
function was capable of concatenating either strings or lists. The
strings use case was deprectated a long time ago but still remained.
Because we cannot return `ast.TypeAny` from an interpolation function,
this use case is no longer supported for strings - `concat` is only
capable of concatenating lists. This should not be a huge issue - the
type checker picks up incorrect parameters, and the native HIL string
concatenation - or the `join` function - can be used to replicate the
missing behaviour.
2016-04-22 02:03:24 +02:00
|
|
|
|
|
|
|
var s []interface{}
|
2014-10-10 00:55:22 +02:00
|
|
|
switch v := raw.Interface().(type) {
|
|
|
|
case []interface{}:
|
|
|
|
s = v
|
|
|
|
case []map[string]interface{}:
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
split := false
|
core: support native list variables in config
This commit adds support for native list variables and outputs, building
up on the previous change to state. Interpolation functions now return
native lists in preference to StringList.
List variables are defined like this:
variable "test" {
# This can also be inferred
type = "list"
default = ["Hello", "World"]
}
output "test_out" {
value = "${var.a_list}"
}
This results in the following state:
```
...
"outputs": {
"test_out": [
"hello",
"world"
]
},
...
```
And the result of terraform output is as follows:
```
$ terraform output
test_out = [
hello
world
]
```
Using the output name, an xargs-friendly representation is output:
```
$ terraform output test_out
hello
world
```
The output command also supports indexing into the list (with
appropriate range checking and no wrapping):
```
$ terraform output test_out 1
world
```
Along with maps, list outputs from one module may be passed as variables
into another, removing the need for the `join(",", var.list_as_string)`
and `split(",", var.list_as_string)` which was previously necessary in
Terraform configuration.
This commit also updates the tests and implementations of built-in
interpolation functions to take and return native lists where
appropriate.
A backwards compatibility note: previously the concat interpolation
function was capable of concatenating either strings or lists. The
strings use case was deprectated a long time ago but still remained.
Because we cannot return `ast.TypeAny` from an interpolation function,
this use case is no longer supported for strings - `concat` is only
capable of concatenating lists. This should not be a huge issue - the
type checker picks up incorrect parameters, and the native HIL string
concatenation - or the `join` function - can be used to replicate the
missing behaviour.
2016-04-22 02:03:24 +02:00
|
|
|
for _, val := range s {
|
|
|
|
if varVal, ok := val.(ast.Variable); ok && varVal.Type == ast.TypeList {
|
|
|
|
split = true
|
2014-10-10 00:55:22 +02:00
|
|
|
}
|
core: support native list variables in config
This commit adds support for native list variables and outputs, building
up on the previous change to state. Interpolation functions now return
native lists in preference to StringList.
List variables are defined like this:
variable "test" {
# This can also be inferred
type = "list"
default = ["Hello", "World"]
}
output "test_out" {
value = "${var.a_list}"
}
This results in the following state:
```
...
"outputs": {
"test_out": [
"hello",
"world"
]
},
...
```
And the result of terraform output is as follows:
```
$ terraform output
test_out = [
hello
world
]
```
Using the output name, an xargs-friendly representation is output:
```
$ terraform output test_out
hello
world
```
The output command also supports indexing into the list (with
appropriate range checking and no wrapping):
```
$ terraform output test_out 1
world
```
Along with maps, list outputs from one module may be passed as variables
into another, removing the need for the `join(",", var.list_as_string)`
and `split(",", var.list_as_string)` which was previously necessary in
Terraform configuration.
This commit also updates the tests and implementations of built-in
interpolation functions to take and return native lists where
appropriate.
A backwards compatibility note: previously the concat interpolation
function was capable of concatenating either strings or lists. The
strings use case was deprectated a long time ago but still remained.
Because we cannot return `ast.TypeAny` from an interpolation function,
this use case is no longer supported for strings - `concat` is only
capable of concatenating lists. This should not be a huge issue - the
type checker picks up incorrect parameters, and the native HIL string
concatenation - or the `join` function - can be used to replicate the
missing behaviour.
2016-04-22 02:03:24 +02:00
|
|
|
if _, ok := val.([]interface{}); ok {
|
2014-10-10 00:55:22 +02:00
|
|
|
split = true
|
|
|
|
}
|
|
|
|
}
|
core: support native list variables in config
This commit adds support for native list variables and outputs, building
up on the previous change to state. Interpolation functions now return
native lists in preference to StringList.
List variables are defined like this:
variable "test" {
# This can also be inferred
type = "list"
default = ["Hello", "World"]
}
output "test_out" {
value = "${var.a_list}"
}
This results in the following state:
```
...
"outputs": {
"test_out": [
"hello",
"world"
]
},
...
```
And the result of terraform output is as follows:
```
$ terraform output
test_out = [
hello
world
]
```
Using the output name, an xargs-friendly representation is output:
```
$ terraform output test_out
hello
world
```
The output command also supports indexing into the list (with
appropriate range checking and no wrapping):
```
$ terraform output test_out 1
world
```
Along with maps, list outputs from one module may be passed as variables
into another, removing the need for the `join(",", var.list_as_string)`
and `split(",", var.list_as_string)` which was previously necessary in
Terraform configuration.
This commit also updates the tests and implementations of built-in
interpolation functions to take and return native lists where
appropriate.
A backwards compatibility note: previously the concat interpolation
function was capable of concatenating either strings or lists. The
strings use case was deprectated a long time ago but still remained.
Because we cannot return `ast.TypeAny` from an interpolation function,
this use case is no longer supported for strings - `concat` is only
capable of concatenating lists. This should not be a huge issue - the
type checker picks up incorrect parameters, and the native HIL string
concatenation - or the `join` function - can be used to replicate the
missing behaviour.
2016-04-22 02:03:24 +02:00
|
|
|
|
2014-10-10 00:55:22 +02:00
|
|
|
if !split {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
core: support native list variables in config
This commit adds support for native list variables and outputs, building
up on the previous change to state. Interpolation functions now return
native lists in preference to StringList.
List variables are defined like this:
variable "test" {
# This can also be inferred
type = "list"
default = ["Hello", "World"]
}
output "test_out" {
value = "${var.a_list}"
}
This results in the following state:
```
...
"outputs": {
"test_out": [
"hello",
"world"
]
},
...
```
And the result of terraform output is as follows:
```
$ terraform output
test_out = [
hello
world
]
```
Using the output name, an xargs-friendly representation is output:
```
$ terraform output test_out
hello
world
```
The output command also supports indexing into the list (with
appropriate range checking and no wrapping):
```
$ terraform output test_out 1
world
```
Along with maps, list outputs from one module may be passed as variables
into another, removing the need for the `join(",", var.list_as_string)`
and `split(",", var.list_as_string)` which was previously necessary in
Terraform configuration.
This commit also updates the tests and implementations of built-in
interpolation functions to take and return native lists where
appropriate.
A backwards compatibility note: previously the concat interpolation
function was capable of concatenating either strings or lists. The
strings use case was deprectated a long time ago but still remained.
Because we cannot return `ast.TypeAny` from an interpolation function,
this use case is no longer supported for strings - `concat` is only
capable of concatenating lists. This should not be a huge issue - the
type checker picks up incorrect parameters, and the native HIL string
concatenation - or the `join` function - can be used to replicate the
missing behaviour.
2016-04-22 02:03:24 +02:00
|
|
|
result := make([]interface{}, 0)
|
2014-10-10 00:55:22 +02:00
|
|
|
for _, v := range s {
|
core: support native list variables in config
This commit adds support for native list variables and outputs, building
up on the previous change to state. Interpolation functions now return
native lists in preference to StringList.
List variables are defined like this:
variable "test" {
# This can also be inferred
type = "list"
default = ["Hello", "World"]
}
output "test_out" {
value = "${var.a_list}"
}
This results in the following state:
```
...
"outputs": {
"test_out": [
"hello",
"world"
]
},
...
```
And the result of terraform output is as follows:
```
$ terraform output
test_out = [
hello
world
]
```
Using the output name, an xargs-friendly representation is output:
```
$ terraform output test_out
hello
world
```
The output command also supports indexing into the list (with
appropriate range checking and no wrapping):
```
$ terraform output test_out 1
world
```
Along with maps, list outputs from one module may be passed as variables
into another, removing the need for the `join(",", var.list_as_string)`
and `split(",", var.list_as_string)` which was previously necessary in
Terraform configuration.
This commit also updates the tests and implementations of built-in
interpolation functions to take and return native lists where
appropriate.
A backwards compatibility note: previously the concat interpolation
function was capable of concatenating either strings or lists. The
strings use case was deprectated a long time ago but still remained.
Because we cannot return `ast.TypeAny` from an interpolation function,
this use case is no longer supported for strings - `concat` is only
capable of concatenating lists. This should not be a huge issue - the
type checker picks up incorrect parameters, and the native HIL string
concatenation - or the `join` function - can be used to replicate the
missing behaviour.
2016-04-22 02:03:24 +02:00
|
|
|
switch val := v.(type) {
|
|
|
|
case ast.Variable:
|
|
|
|
switch val.Type {
|
|
|
|
case ast.TypeList:
|
|
|
|
elements := val.Value.([]ast.Variable)
|
|
|
|
for _, element := range elements {
|
|
|
|
result = append(result, element.Value)
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
result = append(result, val.Value)
|
|
|
|
}
|
|
|
|
case []interface{}:
|
|
|
|
for _, element := range val {
|
|
|
|
result = append(result, element)
|
2015-06-26 00:55:51 +02:00
|
|
|
}
|
core: support native list variables in config
This commit adds support for native list variables and outputs, building
up on the previous change to state. Interpolation functions now return
native lists in preference to StringList.
List variables are defined like this:
variable "test" {
# This can also be inferred
type = "list"
default = ["Hello", "World"]
}
output "test_out" {
value = "${var.a_list}"
}
This results in the following state:
```
...
"outputs": {
"test_out": [
"hello",
"world"
]
},
...
```
And the result of terraform output is as follows:
```
$ terraform output
test_out = [
hello
world
]
```
Using the output name, an xargs-friendly representation is output:
```
$ terraform output test_out
hello
world
```
The output command also supports indexing into the list (with
appropriate range checking and no wrapping):
```
$ terraform output test_out 1
world
```
Along with maps, list outputs from one module may be passed as variables
into another, removing the need for the `join(",", var.list_as_string)`
and `split(",", var.list_as_string)` which was previously necessary in
Terraform configuration.
This commit also updates the tests and implementations of built-in
interpolation functions to take and return native lists where
appropriate.
A backwards compatibility note: previously the concat interpolation
function was capable of concatenating either strings or lists. The
strings use case was deprectated a long time ago but still remained.
Because we cannot return `ast.TypeAny` from an interpolation function,
this use case is no longer supported for strings - `concat` is only
capable of concatenating lists. This should not be a huge issue - the
type checker picks up incorrect parameters, and the native HIL string
concatenation - or the `join` function - can be used to replicate the
missing behaviour.
2016-04-22 02:03:24 +02:00
|
|
|
default:
|
|
|
|
result = append(result, v)
|
2014-10-10 00:55:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-10 01:12:30 +02:00
|
|
|
w.replaceCurrent(reflect.ValueOf(result))
|
2014-10-10 00:55:22 +02:00
|
|
|
}
|