From 2fffec954582d478be836ad20f612e55573adc96 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 18 Apr 2015 15:56:43 -0700 Subject: [PATCH] terraform: inner-count dependencies work [GH-1540] --- terraform/graph_config_node.go | 19 ++++++++++++ .../transform-resource-count-basic/main.tf | 1 - .../transform-resource-count-deps/main.tf | 8 +++++ terraform/transform_resource.go | 30 +++++++++++++++++-- terraform/transform_resource_test.go | 28 +++++++++++++++-- 5 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 terraform/test-fixtures/transform-resource-count-deps/main.tf diff --git a/terraform/graph_config_node.go b/terraform/graph_config_node.go index 791431a71..e83c9a865 100644 --- a/terraform/graph_config_node.go +++ b/terraform/graph_config_node.go @@ -279,6 +279,25 @@ func (n *GraphNodeConfigResource) DependentOn() []string { return result } +// VarWalk calls a callback for all the variables that this resource +// depends on. +func (n *GraphNodeConfigResource) VarWalk(fn func(config.InterpolatedVariable)) { + for _, v := range n.Resource.RawCount.Variables { + fn(v) + } + for _, v := range n.Resource.RawConfig.Variables { + fn(v) + } + for _, p := range n.Resource.Provisioners { + for _, v := range p.ConnInfo.Variables { + fn(v) + } + for _, v := range p.RawConfig.Variables { + fn(v) + } + } +} + func (n *GraphNodeConfigResource) Name() string { result := n.Resource.Id() switch n.DestroyMode { diff --git a/terraform/test-fixtures/transform-resource-count-basic/main.tf b/terraform/test-fixtures/transform-resource-count-basic/main.tf index 83bdd56e6..782a9142e 100644 --- a/terraform/test-fixtures/transform-resource-count-basic/main.tf +++ b/terraform/test-fixtures/transform-resource-count-basic/main.tf @@ -1,4 +1,3 @@ resource "aws_instance" "foo" { count = 3 - value = "${aws_instance.foo.0.value}" } diff --git a/terraform/test-fixtures/transform-resource-count-deps/main.tf b/terraform/test-fixtures/transform-resource-count-deps/main.tf new file mode 100644 index 000000000..c6a683e6e --- /dev/null +++ b/terraform/test-fixtures/transform-resource-count-deps/main.tf @@ -0,0 +1,8 @@ +resource "aws_instance" "foo" { + count = 2 + + provisioner "local-exec" { + command = "echo ${aws_instance.foo.0.id}" + other = "echo ${aws_instance.foo.id}" + } +} diff --git a/terraform/transform_resource.go b/terraform/transform_resource.go index 316883637..ff9f67286 100644 --- a/terraform/transform_resource.go +++ b/terraform/transform_resource.go @@ -134,8 +134,34 @@ func (n *graphNodeExpandedResource) DependableName() []string { // GraphNodeDependent impl. func (n *graphNodeExpandedResource) DependentOn() []string { - config := &GraphNodeConfigResource{Resource: n.Resource} - return config.DependentOn() + configNode := &GraphNodeConfigResource{Resource: n.Resource} + result := configNode.DependentOn() + + // Walk the variables to find any count-specific variables we depend on. + configNode.VarWalk(func(v config.InterpolatedVariable) { + rv, ok := v.(*config.ResourceVariable) + if !ok { + return + } + + // We only want ourselves + if rv.ResourceId() != n.Resource.Id() { + return + } + + // If this isn't a multi-access (which shouldn't be allowed but + // is verified elsewhere), then we depend on the specific count + // of this resource, ignoring ourself (which again should be + // validated elsewhere). + if rv.Index > -1 { + id := fmt.Sprintf("%s.%d", rv.ResourceId(), rv.Index) + if id != n.stateId() && id != n.stateId()+".0" { + result = append(result, id) + } + } + }) + + return result } // GraphNodeProviderConsumer diff --git a/terraform/transform_resource_test.go b/terraform/transform_resource_test.go index 15c29d43e..6933c622c 100644 --- a/terraform/transform_resource_test.go +++ b/terraform/transform_resource_test.go @@ -37,11 +37,33 @@ func TestResourceCountTransformer_countNegative(t *testing.T) { } } +func TestResourceCountTransformer_deps(t *testing.T) { + cfg := testModule(t, "transform-resource-count-deps").Config() + resource := cfg.Resources[0] + + g := Graph{Path: RootModulePath} + { + tf := &ResourceCountTransformer{Resource: resource} + if err := tf.Transform(&g); err != nil { + t.Fatalf("err: %s", err) + } + } + + actual := strings.TrimSpace(g.String()) + expected := strings.TrimSpace(testResourceCountTransformDepsStr) + if actual != expected { + t.Fatalf("bad:\n\n%s", actual) + } +} + const testResourceCountTransformStr = ` aws_instance.foo #0 - aws_instance.foo #2 aws_instance.foo #1 - aws_instance.foo #2 aws_instance.foo #2 - aws_instance.foo #2 +` + +const testResourceCountTransformDepsStr = ` +aws_instance.foo #0 +aws_instance.foo #1 + aws_instance.foo #0 `