From 52bc9a1055700221aa2b29a202512e4945524b58 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 30 Aug 2014 17:25:34 -0700 Subject: [PATCH] core: check sets for computed [GH-247] --- CHANGELOG.md | 3 ++ terraform/context.go | 30 ++++++++++++++----- terraform/context_test.go | 23 ++++++++++++++ terraform/terraform_test.go | 16 ++++++++++ .../test-fixtures/plan-computed-list/main.tf | 8 +++++ 5 files changed, 72 insertions(+), 8 deletions(-) create mode 100644 terraform/test-fixtures/plan-computed-list/main.tf diff --git a/CHANGELOG.md b/CHANGELOG.md index 8096421a3..935fd2c99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ BUG FIXES: * core: Configuration parses when identifier and '=' have no space. [GH-243] * core: `depends_on` with `count` generates the proper graph. [GH-244] + * core: Depending on a computed variable of a list type generates a + plan without failure. i.e. `${type.name.foos.0.bar}` where `foos` + is computed. [GH-247] ## 0.2.0 (August 28, 2014) diff --git a/terraform/context.go b/terraform/context.go index 568c02875..9f462a8dc 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -367,16 +367,30 @@ func (c *Context) computeResourceVariable( } attr, ok := r.Attributes[v.Field] - if !ok { - return "", fmt.Errorf( - "Resource '%s' does not have attribute '%s' "+ - "for variable '%s'", - id, - v.Field, - v.FullKey()) + if ok { + return attr, nil } - return attr, nil + // We didn't find the exact field, so lets separate the dots + // and see if anything along the way is a computed set. i.e. if + // we have "foo.0.bar" as the field, check to see if "foo" is + // a computed list. If so, then the whole thing is computed. + parts := strings.Split(v.Field, ".") + if len(parts) > 1 { + for i := 1; i < len(parts); i++ { + key := fmt.Sprintf("%s.#", strings.Join(parts[:i], ".")) + if attr, ok := r.Attributes[key]; ok { + return attr, nil + } + } + } + + return "", fmt.Errorf( + "Resource '%s' does not have attribute '%s' "+ + "for variable '%s'", + id, + v.Field, + v.FullKey()) } func (c *Context) computeResourceMultiVariable( diff --git a/terraform/context_test.go b/terraform/context_test.go index 2557273ed..1b83e892f 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -1418,6 +1418,29 @@ func TestContextPlan_computed(t *testing.T) { } } +func TestContextPlan_computedList(t *testing.T) { + c := testConfig(t, "plan-computed-list") + p := testProvider("aws") + p.DiffFn = testDiffFn + ctx := testContext(t, &ContextOpts{ + Config: c, + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFuncFixed(p), + }, + }) + + plan, err := ctx.Plan(nil) + if err != nil { + t.Fatalf("err: %s", err) + } + + actual := strings.TrimSpace(plan.String()) + expected := strings.TrimSpace(testTerraformPlanComputedListStr) + if actual != expected { + t.Fatalf("bad:\n%s", actual) + } +} + func TestContextPlan_count(t *testing.T) { c := testConfig(t, "plan-count") p := testProvider("aws") diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index b9392c0aa..7d89c3948 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -302,6 +302,22 @@ STATE: ` +const testTerraformPlanComputedListStr = ` +DIFF: + +CREATE: aws_instance.bar + foo: "" => "" + type: "" => "aws_instance" +CREATE: aws_instance.foo + list.#: "" => "" + num: "" => "2" + type: "" => "aws_instance" + +STATE: + + +` + const testTerraformPlanCountStr = ` DIFF: diff --git a/terraform/test-fixtures/plan-computed-list/main.tf b/terraform/test-fixtures/plan-computed-list/main.tf new file mode 100644 index 000000000..dd61d43f2 --- /dev/null +++ b/terraform/test-fixtures/plan-computed-list/main.tf @@ -0,0 +1,8 @@ +resource "aws_instance" "foo" { + num = "2" + compute = "list.#" +} + +resource "aws_instance" "bar" { + foo = "${aws_instance.foo.list.0.bar}" +}