Skip imports on tofu destroy (#2214)

Signed-off-by: Ronny Orot <ronny.orot@gmail.com>
This commit is contained in:
Ronny Orot 2024-11-25 23:52:03 +02:00 committed by GitHub
parent 5d48a940da
commit cf34b0e6a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 81 additions and 1 deletions

View File

@ -60,6 +60,7 @@ BUG FIXES:
* A `module` block's `version` argument now accepts prerelease version selections using a "v" prefix before the version number. Previously this was accepted only for non-prerelease selections. ([#2124])(https://github.com/opentofu/opentofu/issues/2124)
* The `tofu test` command doesn't try to validate mock provider definition by its underlying provider schema now. ([#2140](https://github.com/opentofu/opentofu/pull/2140))
* Type validation for mocks and overrides are now less strict in `tofu test`. ([#2144](https://github.com/opentofu/opentofu/pull/2144))
* Skip imports blocks logic on `tofu destroy` ([#2214](https://github.com/opentofu/opentofu/pull/2214))
INTERNAL CHANGES:

View File

@ -1046,6 +1046,80 @@ resource "test_object" "a" {
}
}
func TestContext2Plan_destroyWithRefresh_skipImport(t *testing.T) {
m := testModuleInline(t, map[string]string{
"main.tf": `
resource "test_object" "a" {
}
resource "test_object" "imported" {
}
import {
to = test_object.imported
id = "123"
}
`,
})
p := simpleMockProvider()
p.ReadResourceResponse = &providers.ReadResourceResponse{
NewState: cty.ObjectVal(map[string]cty.Value{
"test_string": cty.StringVal("foo"),
}),
}
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
ImportedResources: []providers.ImportedResource{
{
TypeName: "test_object",
State: cty.ObjectVal(map[string]cty.Value{
"test_string": cty.StringVal("foo"),
}),
},
},
}
expectedDestroyedAddr := mustResourceInstanceAddr("test_object.a")
state := states.BuildState(func(s *states.SyncState) {
s.SetResourceInstanceCurrent(expectedDestroyedAddr, &states.ResourceInstanceObjectSrc{
AttrsJSON: []byte(`{"arg":"before"}`),
Status: states.ObjectReady,
}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`), addrs.NoKey)
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
})
plan, diags := ctx.Plan(context.Background(), m, state, &PlanOpts{
Mode: plans.DestroyMode,
SkipRefresh: false, // the default
})
assertNoErrors(t, diags)
if plan.PriorState == nil {
t.Fatal("missing plan state")
}
if len(plan.Changes.Resources) > 1 {
t.Fatal("only a single resource should be changed in the plan")
}
changedResource := plan.Changes.Resources[0]
if changedResource.Action != plans.Delete {
t.Errorf("unexpected %s change for %s", changedResource.Action, changedResource.Addr)
}
if !changedResource.Addr.Equal(expectedDestroyedAddr) {
t.Errorf("unexpected change for resource %s instead of %s", changedResource.Addr, expectedDestroyedAddr)
}
}
func TestContext2Plan_destroySkipRefresh(t *testing.T) {
m := testModuleInline(t, map[string]string{
"main.tf": `

View File

@ -156,7 +156,12 @@ func (n *nodeExpandPlannableResource) DynamicExpand(ctx EvalContext) (*Graph, er
importResolver := ctx.ImportResolver()
var diags tfdiags.Diagnostics
for _, importTarget := range n.importTargets {
if importTarget.IsFromImportBlock() {
// If the import target originates from the import command (instead of the import block), we don't need to
// resolve the import as it's already in the resolved form
// In addition, if PreDestroyRefresh is true, we know we are running as part of a refresh plan, immediately before a destroy
// plan. In the destroy plan mode, import blocks are not relevant, that's why we skip resolving imports
skipImports := importTarget.IsFromImportBlock() && !n.preDestroyRefresh
if skipImports {
err := importResolver.ExpandAndResolveImport(importTarget, ctx)
diags = diags.Append(err)
}