diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index 9e390455b2..c58ee803f7 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -2495,6 +2495,94 @@ module.child.subchild.subsubchild: } } +// https://github.com/hashicorp/terraform/issues/5440 +func TestContext2Apply_destroyModuleWithAttrsReferencingResource(t *testing.T) { + m := testModule(t, "apply-destroy-module-with-attrs") + p := testProvider("aws") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + + var state *State + var err error + { + ctx := testContext2(t, &ContextOpts{ + Module: m, + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFuncFixed(p), + }, + Variables: map[string]string{ + "key_name": "foobarkey", + }, + }) + + // First plan and apply a create operation + if _, err := ctx.Plan(); err != nil { + t.Fatalf("err: %s", err) + } + + state, err = ctx.Apply() + if err != nil { + t.Fatalf("err: %s", err) + } + } + + h := new(HookRecordApplyOrder) + h.Active = true + + { + ctx := testContext2(t, &ContextOpts{ + Destroy: true, + Module: m, + State: state, + Hooks: []Hook{h}, + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFuncFixed(p), + }, + Variables: map[string]string{ + "key_name": "foobarkey", + }, + }) + + // First plan and apply a create operation + plan, err := ctx.Plan() + if err != nil { + t.Fatalf("err: %s", err) + } + + var buf bytes.Buffer + if err := WritePlan(plan, &buf); err != nil { + t.Fatalf("err: %s", err) + } + + planFromFile, err := ReadPlan(&buf) + if err != nil { + t.Fatalf("err: %s", err) + } + + ctx = planFromFile.Context(&ContextOpts{ + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFuncFixed(p), + }, + }) + + state, err = ctx.Apply() + if err != nil { + t.Fatalf("err: %s", err) + } + } + + //Test that things were destroyed + actual := strings.TrimSpace(state.String()) + expected := strings.TrimSpace(` + +module.child: + + `) + if actual != expected { + t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) + } +} + func TestContext2Apply_destroyOutputs(t *testing.T) { m := testModule(t, "apply-destroy-outputs") h := new(HookRecordApplyOrder) diff --git a/terraform/graph_config_node_resource.go b/terraform/graph_config_node_resource.go index 8abcd91565..41fc7e5153 100644 --- a/terraform/graph_config_node_resource.go +++ b/terraform/graph_config_node_resource.go @@ -297,6 +297,12 @@ func (n *GraphNodeConfigResource) Noop(opts *NoopOpts) bool { return true } + // If the whole module is being destroyed, then the resource nodes in that + // module are irrelevant - we only need to keep the destroy nodes. + if opts.ModDiff != nil && opts.ModDiff.Destroy == true { + return true + } + // Grab the ID which is the prefix (in the case count > 0 at some point) prefix := n.Resource.Id() diff --git a/terraform/test-fixtures/apply-destroy-module-with-attrs/child/main.tf b/terraform/test-fixtures/apply-destroy-module-with-attrs/child/main.tf new file mode 100644 index 0000000000..2aa1e1045a --- /dev/null +++ b/terraform/test-fixtures/apply-destroy-module-with-attrs/child/main.tf @@ -0,0 +1,5 @@ +variable "vpc_id" {} + +resource "aws_instance" "child" { + vpc_id = "${var.vpc_id}" +} diff --git a/terraform/test-fixtures/apply-destroy-module-with-attrs/main.tf b/terraform/test-fixtures/apply-destroy-module-with-attrs/main.tf new file mode 100644 index 0000000000..0f26089ff6 --- /dev/null +++ b/terraform/test-fixtures/apply-destroy-module-with-attrs/main.tf @@ -0,0 +1,6 @@ +resource "aws_instance" "vpc" { } + +module "child" { + source = "./child" + vpc_id = "${aws_instance.vpc.id}" +}