prune unused providers within modules

The logic used to prune unused providers was only taking into account
the common case of providers in the root module. The quick check of
looking for up edges doesn't work within a module, because the module
structures will create non-resource nodes connected to the providers.
Use a deeper check of looking for any dependent resources which may
require that provider to be configured.
This commit is contained in:
James Bardin 2023-04-17 13:48:04 -04:00
parent f0b3b74f7c
commit 2c09ae4f3d
2 changed files with 55 additions and 4 deletions

View File

@ -2042,3 +2042,46 @@ resource "test_resource" "b" {
_, diags = ctx.Apply(plan, m) _, diags = ctx.Apply(plan, m)
assertNoErrors(t, diags) 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)
}

View File

@ -348,10 +348,18 @@ func (t *pruneUnusedNodesTransformer) Transform(g *Graph) error {
} }
case GraphNodeProvider: case GraphNodeProvider:
// Providers that may have been required by expansion nodes // Only keep providers for evaluation if they have
// that we no longer need can also be removed. // resources to handle.
if g.UpEdges(n).Len() > 0 { // The provider transformers removed most unused providers
return // 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: default: