diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index bd362668f..a4595bada 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -8828,6 +8828,52 @@ module.child: `) } +func TestContext2Apply_targetedResourceOrphanModule(t *testing.T) { + m := testModule(t, "apply-targeted-resource-orphan-module") + p := testProvider("aws") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + + // Create a state with an orphan module + state := MustShimLegacyState(&State{ + Modules: []*ModuleState{ + &ModuleState{ + Path: []string{"root", "child"}, + Resources: map[string]*ResourceState{ + "aws_instance.bar": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{}, + Provider: "provider.aws", + }, + }, + }, + }, + }) + + ctx := testContext2(t, &ContextOpts{ + Config: m, + ProviderResolver: providers.ResolverFixed( + map[string]providers.Factory{ + "aws": testProviderFuncFixed(p), + }, + ), + State: state, + Targets: []addrs.Targetable{ + addrs.RootModuleInstance.Resource( + addrs.ManagedResourceMode, "aws_instance", "foo", + ), + }, + }) + + if _, diags := ctx.Plan(); diags.HasErrors() { + t.Fatalf("plan errors: %s", diags.Err()) + } + + if _, diags := ctx.Apply(); diags.HasErrors() { + t.Fatalf("apply errors: %s", diags.Err()) + } +} + func TestContext2Apply_unknownAttribute(t *testing.T) { m := testModule(t, "apply-unknown") p := testProvider("aws") diff --git a/terraform/node_module_removed.go b/terraform/node_module_removed.go index cb55a1a88..99e440903 100644 --- a/terraform/node_module_removed.go +++ b/terraform/node_module_removed.go @@ -14,6 +14,7 @@ type NodeModuleRemoved struct { var ( _ GraphNodeSubPath = (*NodeModuleRemoved)(nil) + _ RemovableIfNotTargeted = (*NodeModuleRemoved)(nil) _ GraphNodeEvalable = (*NodeModuleRemoved)(nil) _ GraphNodeReferencer = (*NodeModuleRemoved)(nil) _ GraphNodeReferenceOutside = (*NodeModuleRemoved)(nil) @@ -63,6 +64,13 @@ func (n *NodeModuleRemoved) References() []*addrs.Reference { } } +// RemovableIfNotTargeted +func (n *NodeModuleRemoved) RemoveIfNotTargeted() bool { + // We need to add this so that this node will be removed if + // it isn't targeted or a dependency of a target. + return true +} + // EvalCheckModuleRemoved is an EvalNode implementation that verifies that // a module has been removed from the state as expected. type EvalCheckModuleRemoved struct { diff --git a/terraform/testdata/apply-targeted-resource-orphan-module/child/main.tf b/terraform/testdata/apply-targeted-resource-orphan-module/child/main.tf new file mode 100644 index 000000000..6ff716a4d --- /dev/null +++ b/terraform/testdata/apply-targeted-resource-orphan-module/child/main.tf @@ -0,0 +1 @@ +resource "aws_instance" "bar" {} diff --git a/terraform/testdata/apply-targeted-resource-orphan-module/main.tf b/terraform/testdata/apply-targeted-resource-orphan-module/main.tf new file mode 100644 index 000000000..0c15c4bb2 --- /dev/null +++ b/terraform/testdata/apply-targeted-resource-orphan-module/main.tf @@ -0,0 +1,5 @@ +//module "child" { +// source = "./child" +//} + +resource "aws_instance" "foo" {}