diff --git a/internal/terraform/context_apply2_test.go b/internal/terraform/context_apply2_test.go index 18f46768b1..c9d4aad1ba 100644 --- a/internal/terraform/context_apply2_test.go +++ b/internal/terraform/context_apply2_test.go @@ -2042,3 +2042,46 @@ resource "test_resource" "b" { _, diags = ctx.Apply(plan, m) assertNoErrors(t, diags) } + +func TestContext2Apply_destroyUnusedModuleProvider(t *testing.T) { + // an unsued provider within a module should not be called during destroy + unusedProvider := testProvider("unused") + testProvider := testProvider("test") + ctx := testContext2(t, &ContextOpts{ + Providers: map[addrs.Provider]providers.Factory{ + addrs.NewDefaultProvider("test"): testProviderFuncFixed(testProvider), + addrs.NewDefaultProvider("unused"): testProviderFuncFixed(unusedProvider), + }, + }) + + unusedProvider.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { + resp.Diagnostics = resp.Diagnostics.Append(errors.New("configuration failed")) + return resp + } + + m := testModuleInline(t, map[string]string{ + "main.tf": ` +module "mod" { + source = "./mod" +} + +resource "test_resource" "test" { +} +`, + + "mod/main.tf": ` +provider "unused" { +} + +resource "unused_resource" "test" { +} +`, + }) + + plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{ + Mode: plans.DestroyMode, + }) + assertNoErrors(t, diags) + _, diags = ctx.Apply(plan, m) + assertNoErrors(t, diags) +} diff --git a/internal/terraform/transform_destroy_edge.go b/internal/terraform/transform_destroy_edge.go index 2d6fb7083f..357bfca8ab 100644 --- a/internal/terraform/transform_destroy_edge.go +++ b/internal/terraform/transform_destroy_edge.go @@ -348,10 +348,18 @@ func (t *pruneUnusedNodesTransformer) Transform(g *Graph) error { } case GraphNodeProvider: - // Providers that may have been required by expansion nodes - // that we no longer need can also be removed. - if g.UpEdges(n).Len() > 0 { - return + // Only keep providers for evaluation if they have + // resources to handle. + // The provider transformers removed most unused providers + // earlier, however there may be more to prune now based on + // targeting or a destroy with no related instances in the + // state. + des, _ := g.Descendents(n) + for _, v := range des { + switch v.(type) { + case GraphNodeProviderConsumer: + return + } } default: