From 2802d319d29893e5b7b882590a16294cceddbc49 Mon Sep 17 00:00:00 2001 From: Chris Marchesi Date: Wed, 19 Apr 2017 16:56:54 -0700 Subject: [PATCH] core: Move CountBoundaryTransformer to the plan graph builder This fixes interpolation issues on grandchild data sources that have multiple instances (ie: counts). For example, baz depends on bar, which depends on foo. In this instance, after an initial TF run is done and state is saved, the next refresh/plan is not properly transformed, and instead of the graph/state coming through as data.x.bar.0, it comes through as data.x.bar. This breaks interpolations that rely on splat operators - ie: data.x.bar.*.out. --- builtin/providers/test/data_source_test.go | 56 ++++++++++++++++++++++ terraform/graph_builder_apply.go | 3 -- terraform/graph_builder_plan.go | 3 ++ 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/builtin/providers/test/data_source_test.go b/builtin/providers/test/data_source_test.go index 3f4e5ada61..44622c0c56 100644 --- a/builtin/providers/test/data_source_test.go +++ b/builtin/providers/test/data_source_test.go @@ -99,3 +99,59 @@ resource "test_resource" "foo" { }, }) } + +// Test that a grandchild data source that is based off of count works, ie: +// dependency chain foo -> bar -> baz. This was failing because +// CountBoundaryTransformer is being run during apply instead of plan, which +// meant that it wasn't firing after data sources were potentially changing +// state and causing diff/interpolation issues. +// +// This happens after the initial apply, after state is saved. +func TestDataSource_dataSourceCountGrandChild(t *testing.T) { + resource.UnitTest(t, resource.TestCase{ + Providers: testAccProviders, + CheckDestroy: func(s *terraform.State) error { + return nil + }, + Steps: []resource.TestStep{ + { + Config: dataSourceCountGrandChildConfig, + }, + { + Config: dataSourceCountGrandChildConfig, + Check: func(s *terraform.State) error { + for _, v := range []string{"foo", "bar", "baz"} { + count := 0 + for k := range s.RootModule().Resources { + if strings.HasPrefix(k, fmt.Sprintf("data.test_data_source.%s.", v)) { + count++ + } + } + + if count != 2 { + return fmt.Errorf("bad count for data.test_data_source.%s: %d", v, count) + } + } + return nil + }, + }, + }, + }) +} + +const dataSourceCountGrandChildConfig = ` +data "test_data_source" "foo" { + count = 2 + input = "one" +} + +data "test_data_source" "bar" { + count = "${length(data.test_data_source.foo.*.id)}" + input = "${data.test_data_source.foo.*.output[count.index]}" +} + +data "test_data_source" "baz" { + count = "${length(data.test_data_source.bar.*.id)}" + input = "${data.test_data_source.bar.*.output[count.index]}" +} +` diff --git a/terraform/graph_builder_apply.go b/terraform/graph_builder_apply.go index 38a90f2775..251b517e1d 100644 --- a/terraform/graph_builder_apply.go +++ b/terraform/graph_builder_apply.go @@ -117,9 +117,6 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer { // Connect references so ordering is correct &ReferenceTransformer{}, - // Add the node to fix the state count boundaries - &CountBoundaryTransformer{}, - // Target &TargetsTransformer{Targets: b.Targets}, diff --git a/terraform/graph_builder_plan.go b/terraform/graph_builder_plan.go index 02d869700e..b8ba4da107 100644 --- a/terraform/graph_builder_plan.go +++ b/terraform/graph_builder_plan.go @@ -120,6 +120,9 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer { &CloseProviderTransformer{}, &CloseProvisionerTransformer{}, + // Add the node to fix the state count boundaries + &CountBoundaryTransformer{}, + // Single root &RootTransformer{}, }