fix: bug when deleting a resource using enabled on tofu plan -out (#3566)

Signed-off-by: Diogenes Fernandes <diofeher@gmail.com>
This commit is contained in:
Diógenes Fernandes
2025-12-10 12:31:50 -03:00
committed by GitHub
parent 267022ca8c
commit e1b159b015
4 changed files with 119 additions and 2 deletions

View File

@@ -166,6 +166,7 @@ const (
ResourceInstanceActionReason_READ_BECAUSE_DEPENDENCY_PENDING ResourceInstanceActionReason = 11
ResourceInstanceActionReason_READ_BECAUSE_CHECK_NESTED ResourceInstanceActionReason = 13
ResourceInstanceActionReason_DELETE_BECAUSE_NO_MOVE_TARGET ResourceInstanceActionReason = 12
ResourceInstanceActionReason_DELETE_BECAUSE_ENABLED_FALSE ResourceInstanceActionReason = 14
)
// Enum value maps for ResourceInstanceActionReason.
@@ -185,6 +186,7 @@ var (
11: "READ_BECAUSE_DEPENDENCY_PENDING",
13: "READ_BECAUSE_CHECK_NESTED",
12: "DELETE_BECAUSE_NO_MOVE_TARGET",
14: "DELETE_BECAUSE_ENABLED_FALSE",
}
ResourceInstanceActionReason_value = map[string]int32{
"NONE": 0,
@@ -201,6 +203,7 @@ var (
"READ_BECAUSE_DEPENDENCY_PENDING": 11,
"READ_BECAUSE_CHECK_NESTED": 13,
"DELETE_BECAUSE_NO_MOVE_TARGET": 12,
"DELETE_BECAUSE_ENABLED_FALSE": 14,
}
)
@@ -1444,7 +1447,7 @@ const file_planfile_proto_rawDesc = "" +
"\x12CREATE_THEN_DELETE\x10\a\x12\n" +
"\n" +
"\x06FORGET\x10\b\x12\b\n" +
"\x04OPEN\x10\t*\xc8\x03\n" +
"\x04OPEN\x10\t*\xea\x03\n" +
"\x1cResourceInstanceActionReason\x12\b\n" +
"\x04NONE\x10\x00\x12\x1b\n" +
"\x17REPLACE_BECAUSE_TAINTED\x10\x01\x12\x16\n" +
@@ -1460,7 +1463,8 @@ const file_planfile_proto_rawDesc = "" +
"\x12#\n" +
"\x1fREAD_BECAUSE_DEPENDENCY_PENDING\x10\v\x12\x1d\n" +
"\x19READ_BECAUSE_CHECK_NESTED\x10\r\x12!\n" +
"\x1dDELETE_BECAUSE_NO_MOVE_TARGET\x10\fB@Z>github.com/opentofu/opentofu/internal/plans/internal/planprotob\x06proto3"
"\x1dDELETE_BECAUSE_NO_MOVE_TARGET\x10\f\x12 \n" +
"\x1cDELETE_BECAUSE_ENABLED_FALSE\x10\x0eB@Z>github.com/opentofu/opentofu/internal/plans/internal/planprotob\x06proto3"
var (
file_planfile_proto_rawDescOnce sync.Once

View File

@@ -185,6 +185,7 @@ enum ResourceInstanceActionReason {
READ_BECAUSE_DEPENDENCY_PENDING = 11;
READ_BECAUSE_CHECK_NESTED = 13;
DELETE_BECAUSE_NO_MOVE_TARGET = 12;
DELETE_BECAUSE_ENABLED_FALSE = 14;
}
message ResourceInstanceChange {

View File

@@ -364,6 +364,8 @@ func resourceChangeFromTfplan(rawChange *planproto.ResourceInstanceChange) (*pla
ret.ActionReason = plans.ResourceInstanceReadBecauseCheckNested
case planproto.ResourceInstanceActionReason_DELETE_BECAUSE_NO_MOVE_TARGET:
ret.ActionReason = plans.ResourceInstanceDeleteBecauseNoMoveTarget
case planproto.ResourceInstanceActionReason_DELETE_BECAUSE_ENABLED_FALSE:
ret.ActionReason = plans.ResourceInstanceDeleteBecauseEnabledFalse
default:
return nil, fmt.Errorf("resource has invalid action reason %s", rawChange.ActionReason)
}
@@ -771,6 +773,8 @@ func resourceChangeToTfplan(change *plans.ResourceInstanceChangeSrc) (*planproto
ret.ActionReason = planproto.ResourceInstanceActionReason_READ_BECAUSE_CHECK_NESTED
case plans.ResourceInstanceDeleteBecauseNoMoveTarget:
ret.ActionReason = planproto.ResourceInstanceActionReason_DELETE_BECAUSE_NO_MOVE_TARGET
case plans.ResourceInstanceDeleteBecauseEnabledFalse:
ret.ActionReason = planproto.ResourceInstanceActionReason_DELETE_BECAUSE_ENABLED_FALSE
default:
return nil, fmt.Errorf("resource %s has unsupported action reason %s", change.Addr, change.ActionReason)
}

View File

@@ -473,3 +473,111 @@ func TestTFPlanRoundTripDestroy(t *testing.T) {
}
}
}
func TestTFPlanChangeReasonsEncoding(t *testing.T) {
tests := []struct {
name string
action plans.Action
actionReason plans.ResourceInstanceChangeActionReason
}{
{
name: "ResourceInstanceDeleteBecauseEnabledFalse",
action: plans.Delete,
actionReason: plans.ResourceInstanceDeleteBecauseEnabledFalse,
},
{
name: "ResourceInstanceDeleteBecauseNoResourceConfig",
action: plans.Delete,
actionReason: plans.ResourceInstanceDeleteBecauseNoResourceConfig,
},
{
name: "ResourceInstanceDeleteBecauseWrongRepetition",
action: plans.Delete,
actionReason: plans.ResourceInstanceDeleteBecauseWrongRepetition,
},
{
name: "ResourceInstanceDeleteBecauseCountIndex",
action: plans.Delete,
actionReason: plans.ResourceInstanceDeleteBecauseCountIndex,
},
{
name: "ResourceInstanceDeleteBecauseEachKey",
action: plans.Delete,
actionReason: plans.ResourceInstanceDeleteBecauseEachKey,
},
{
name: "ResourceInstanceDeleteBecauseNoModule",
action: plans.Delete,
actionReason: plans.ResourceInstanceDeleteBecauseNoModule,
},
{
name: "ResourceInstanceDeleteBecauseNoMoveTarget",
action: plans.Delete,
actionReason: plans.ResourceInstanceDeleteBecauseNoMoveTarget,
},
}
for _, test := range tests {
objTy := cty.Object(map[string]cty.Type{
"id": cty.String,
})
plan := &plans.Plan{
Backend: plans.Backend{
Type: "local",
Config: mustNewDynamicValue(
cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("bar"),
}),
cty.Object(map[string]cty.Type{
"foo": cty.String,
}),
),
Workspace: "default",
},
Changes: &plans.Changes{
Resources: []*plans.ResourceInstanceChangeSrc{
{
Addr: addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_thing",
Name: "woot",
}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
PrevRunAddr: addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_thing",
Name: "woot",
}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance),
ProviderAddr: addrs.AbsProviderConfig{
Provider: addrs.NewDefaultProvider("test"),
Module: addrs.RootModule,
},
ChangeSrc: plans.ChangeSrc{
Action: test.action,
Before: mustNewDynamicValue(cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("foo-bar-baz"),
}), objTy),
After: mustNewDynamicValue(cty.NullVal(objTy), objTy),
},
ActionReason: test.actionReason,
},
},
},
}
var buf bytes.Buffer
err := writeTfplan(plan, &buf)
if err != nil {
t.Fatal(err)
}
_, err = readTfplan(&buf)
if err != nil {
t.Fatal(err)
}
if err != nil {
t.Fatal("should've succeeded, got error: ", err)
}
}
}