skip refreshing deposed during destroy plan

The destroy plan should not require a configured provider (the complete
configuration is not evaluated, so they cannot be configured).

Deposed instances were being refreshed during the destroy plan, because
this instance type is only ever destroyed and shares the same
implementation between plan and walkPlanDestroy. Skip refreshing during
walkPlanDestroy.
This commit is contained in:
James Bardin 2021-10-07 16:51:24 -04:00
parent ad9944e523
commit 22b400b8de
2 changed files with 53 additions and 1 deletions

View File

@ -549,3 +549,50 @@ resource "test_object" "y" {
}
}
}
func TestContext2Apply_destroyWithDeposed(t *testing.T) {
m := testModuleInline(t, map[string]string{
"main.tf": `
resource "test_object" "x" {
test_string = "ok"
lifecycle {
create_before_destroy = true
}
}`,
})
p := simpleMockProvider()
deposedKey := states.NewDeposedKey()
state := states.NewState()
root := state.EnsureModule(addrs.RootModuleInstance)
root.SetResourceInstanceDeposed(
mustResourceInstanceAddr("test_object.x").Resource,
deposedKey,
&states.ResourceInstanceObjectSrc{
Status: states.ObjectTainted,
AttrsJSON: []byte(`{"test_string":"deposed"}`),
},
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
})
plan, diags := ctx.Plan(m, state, &PlanOpts{
Mode: plans.DestroyMode,
})
if diags.HasErrors() {
t.Fatalf("plan: %s", diags.Err())
}
_, diags = ctx.Apply(plan, m)
if diags.HasErrors() {
t.Fatalf("apply: %s", diags.Err())
}
}

View File

@ -95,7 +95,12 @@ func (n *NodePlanDeposedResourceInstanceObject) Execute(ctx EvalContext, op walk
return diags
}
if !n.skipRefresh {
// We don't refresh during the planDestroy walk, since that is only adding
// the destroy changes to the plan and the provider will not be configured
// at this point. The other nodes use separate types for plan and destroy,
// while deposed instances are always a destroy operation, so the logic
// here is a bit overloaded.
if !n.skipRefresh && op != walkPlanDestroy {
// Refresh this object even though it is going to be destroyed, in
// case it's already been deleted outside of Terraform. If this is a
// normal plan, providers expect a Read request to remove missing