diff --git a/config/interpolate_funcs.go b/config/interpolate_funcs.go index 0ab4ce56b..e912493b6 100644 --- a/config/interpolate_funcs.go +++ b/config/interpolate_funcs.go @@ -667,6 +667,9 @@ func interpolationFuncElement() ast.Function { ReturnType: ast.TypeString, Callback: func(args []interface{}) (interface{}, error) { list := args[0].([]ast.Variable) + if len(list) == 0 { + return nil, fmt.Errorf("element() may not be used with an empty list") + } index, err := strconv.Atoi(args[1].(string)) if err != nil || index < 0 { diff --git a/config/interpolate_funcs_test.go b/config/interpolate_funcs_test.go index 6a69d533a..8bd03b111 100644 --- a/config/interpolate_funcs_test.go +++ b/config/interpolate_funcs_test.go @@ -952,6 +952,7 @@ func TestInterpolateFuncElement(t *testing.T) { Vars: map[string]ast.Variable{ "var.a_list": interfaceToVariableSwallowError([]string{"foo", "baz"}), "var.a_short_list": interfaceToVariableSwallowError([]string{"foo"}), + "var.empty_list": interfaceToVariableSwallowError([]interface{}{}), }, Cases: []testFunctionCase{ { @@ -980,6 +981,13 @@ func TestInterpolateFuncElement(t *testing.T) { true, }, + // Empty list should fail + { + `${element(var.empty_list, 0)}`, + nil, + true, + }, + // Too many args { `${element(var.a_list, "0", "2")}`, diff --git a/terraform/context_input_test.go b/terraform/context_input_test.go index 08e017b4c..f953645c8 100644 --- a/terraform/context_input_test.go +++ b/terraform/context_input_test.go @@ -49,6 +49,27 @@ func TestContext2Input(t *testing.T) { } } +func TestContext2Input_moduleComputedOutputElement(t *testing.T) { + m := testModule(t, "input-module-computed-output-element") + p := testProvider("aws") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + ctx := testContext2(t, &ContextOpts{ + Module: m, + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFuncFixed(p), + }, + }) + + p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { + return c, nil + } + + if err := ctx.Input(InputModeStd); err != nil { + t.Fatalf("err: %s", err) + } +} + func TestContext2Input_badVarDefault(t *testing.T) { m := testModule(t, "input-bad-var-default") p := testProvider("aws") diff --git a/terraform/interpolate.go b/terraform/interpolate.go index f03154141..870fac762 100644 --- a/terraform/interpolate.go +++ b/terraform/interpolate.go @@ -162,7 +162,6 @@ func (i *Interpolater) valueModuleVar( } else { // Same reasons as the comment above. result[n] = unknownVariable() - } } @@ -485,11 +484,15 @@ func (i *Interpolater) computeResourceMultiVariable( err) } - // If we have no module in the state yet or count, return empty - if module == nil || len(module.Resources) == 0 || count == 0 { + // If count is zero, we return an empty list + if count == 0 { return &ast.Variable{Type: ast.TypeList, Value: []ast.Variable{}}, nil } + // If we have no module in the state yet or count, return unknown + if module == nil || len(module.Resources) == 0 { + return &unknownVariable, nil + } var values []string for j := 0; j < count; j++ { id := fmt.Sprintf("%s.%d", v.ResourceId(), j) diff --git a/terraform/state.go b/terraform/state.go index 4ca020685..80691fd82 100644 --- a/terraform/state.go +++ b/terraform/state.go @@ -635,8 +635,7 @@ type OutputState struct { } func (s *OutputState) String() string { - // This is a v0.6.x implementation only - return fmt.Sprintf("%s", s.Value.(string)) + return fmt.Sprintf("%#v", s.Value) } // Equal compares two OutputState structures for equality. nil values are diff --git a/terraform/test-fixtures/input-module-computed-output-element/main.tf b/terraform/test-fixtures/input-module-computed-output-element/main.tf new file mode 100644 index 000000000..bb96e24a3 --- /dev/null +++ b/terraform/test-fixtures/input-module-computed-output-element/main.tf @@ -0,0 +1,9 @@ +module "b" { + source = "./modb" +} + +module "a" { + source = "./moda" + + single_element = "${element(module.b.computed_list, 0)}" +} diff --git a/terraform/test-fixtures/input-module-computed-output-element/moda/main.tf b/terraform/test-fixtures/input-module-computed-output-element/moda/main.tf new file mode 100644 index 000000000..eb09eb192 --- /dev/null +++ b/terraform/test-fixtures/input-module-computed-output-element/moda/main.tf @@ -0,0 +1,3 @@ +variable "single_element" { + type = "string" +} diff --git a/terraform/test-fixtures/input-module-computed-output-element/modb/main.tf b/terraform/test-fixtures/input-module-computed-output-element/modb/main.tf new file mode 100644 index 000000000..ebe4a7eff --- /dev/null +++ b/terraform/test-fixtures/input-module-computed-output-element/modb/main.tf @@ -0,0 +1,7 @@ +resource "aws_instance" "test" { + count = 3 +} + +output "computed_list" { + value = ["${aws_instance.test.*.id}"] +}