From 1d45d12f4077ac9fb0bfc6f19c765c77aefdf4dc Mon Sep 17 00:00:00 2001 From: Daniel Schmidt Date: Thu, 11 Jul 2024 14:28:07 +0200 Subject: [PATCH] stacks: track resource deferrals in apply --- internal/stacks/stackruntime/apply_test.go | 52 +++++++++++++++++++ .../internal/stackeval/component_instance.go | 1 + .../deferred/deferred.tfstack.hcl | 24 +++++++++ .../deferred/deferred/deferred.tf | 14 +++++ .../test/state-manipulation/deferred/ok/ok.tf | 13 +++++ 5 files changed, 104 insertions(+) create mode 100644 internal/stacks/stackruntime/testdata/mainbundle/test/state-manipulation/deferred/deferred.tfstack.hcl create mode 100644 internal/stacks/stackruntime/testdata/mainbundle/test/state-manipulation/deferred/deferred/deferred.tf create mode 100644 internal/stacks/stackruntime/testdata/mainbundle/test/state-manipulation/deferred/ok/ok.tf diff --git a/internal/stacks/stackruntime/apply_test.go b/internal/stacks/stackruntime/apply_test.go index 77b8b29d08..9da15bfe26 100644 --- a/internal/stacks/stackruntime/apply_test.go +++ b/internal/stacks/stackruntime/apply_test.go @@ -1109,6 +1109,58 @@ func TestApplyWithStateManipulation(t *testing.T) { }), expectedWarnings: []string{"Some objects will no longer be managed by Terraform"}, }, + "deferred": { + store: stacks_testing_provider.NewResourceStoreBuilder(). + AddResource("self", cty.ObjectVal(map[string]cty.Value{ + "id": cty.StringVal("deferred"), + "value": cty.UnknownVal(cty.String), + })). + Build(), + changes: []stackstate.AppliedChange{ + &stackstate.AppliedChangeComponentInstance{ + ComponentAddr: mustAbsComponent("component.deferred"), + ComponentInstanceAddr: mustAbsComponentInstance("component.deferred"), + OutputValues: make(map[addrs.OutputValue]cty.Value), + }, + &stackstate.AppliedChangeComponentInstance{ + ComponentAddr: mustAbsComponent("component.ok"), + ComponentInstanceAddr: mustAbsComponentInstance("component.ok"), + OutputValues: make(map[addrs.OutputValue]cty.Value), + }, + &stackstate.AppliedChangeResourceInstanceObject{ + ResourceInstanceObjectAddr: mustAbsResourceInstanceObject("component.ok.testing_resource.self"), + NewStateSrc: &states.ResourceInstanceObjectSrc{ + AttrsJSON: mustMarshalJSONAttrs(map[string]interface{}{ + "id": "ok", + "value": "ok", + }), + Status: states.ObjectReady, + AttrSensitivePaths: nil, + Dependencies: []addrs.ConfigResource{}, + }, + ProviderConfigAddr: mustDefaultRootProvider("testing"), + PreviousResourceInstanceObjectAddr: nil, + Schema: stacks_testing_provider.TestingResourceSchema, + }, + }, + counts: collections.NewMap[stackaddrs.AbsComponentInstance, *hooks.ComponentInstanceChange]( + collections.MapElem[stackaddrs.AbsComponentInstance, *hooks.ComponentInstanceChange]{ + K: mustAbsComponentInstance("component.ok"), + V: &hooks.ComponentInstanceChange{ + Addr: mustAbsComponentInstance("component.ok"), + Add: 1, + Defer: 0, + }, + }, + collections.MapElem[stackaddrs.AbsComponentInstance, *hooks.ComponentInstanceChange]{ + K: mustAbsComponentInstance("component.deferred"), + V: &hooks.ComponentInstanceChange{ + Addr: mustAbsComponentInstance("component.deferred"), + Defer: 1, + }, + }, + ), + }, } for name, tc := range tcs { diff --git a/internal/stacks/stackruntime/internal/stackeval/component_instance.go b/internal/stacks/stackruntime/internal/stackeval/component_instance.go index 4b4f8641ab..453fe11495 100644 --- a/internal/stacks/stackruntime/internal/stackeval/component_instance.go +++ b/internal/stacks/stackruntime/internal/stackeval/component_instance.go @@ -948,6 +948,7 @@ func (c *ComponentInstance) ApplyModuleTreePlan(ctx context.Context, plan *plans cic.Forget++ } } + cic.Defer = plan.DeferredResourceInstanceChanges.Len() hookMore(ctx, seq, h.ReportComponentInstanceApplied, cic) } diff --git a/internal/stacks/stackruntime/testdata/mainbundle/test/state-manipulation/deferred/deferred.tfstack.hcl b/internal/stacks/stackruntime/testdata/mainbundle/test/state-manipulation/deferred/deferred.tfstack.hcl new file mode 100644 index 0000000000..4d61b7e473 --- /dev/null +++ b/internal/stacks/stackruntime/testdata/mainbundle/test/state-manipulation/deferred/deferred.tfstack.hcl @@ -0,0 +1,24 @@ +required_providers { + testing = { + source = "hashicorp/testing" + version = "0.1.0" + } +} + +provider "testing" "default" {} + +component "ok" { + source = "./ok" + + providers = { + testing = provider.testing.default + } +} + +component "deferred" { + source = "./deferred" + + providers = { + testing = provider.testing.default + } +} diff --git a/internal/stacks/stackruntime/testdata/mainbundle/test/state-manipulation/deferred/deferred/deferred.tf b/internal/stacks/stackruntime/testdata/mainbundle/test/state-manipulation/deferred/deferred/deferred.tf new file mode 100644 index 0000000000..4a1e84af45 --- /dev/null +++ b/internal/stacks/stackruntime/testdata/mainbundle/test/state-manipulation/deferred/deferred/deferred.tf @@ -0,0 +1,14 @@ +terraform { + required_providers { + testing = { + source = "hashicorp/testing" + version = "0.1.0" + } + } +} + +resource "testing_deferred_resource" "resource" { + id = "hello" + value = "world" + deferred = true +} diff --git a/internal/stacks/stackruntime/testdata/mainbundle/test/state-manipulation/deferred/ok/ok.tf b/internal/stacks/stackruntime/testdata/mainbundle/test/state-manipulation/deferred/ok/ok.tf new file mode 100644 index 0000000000..4ece07d8e4 --- /dev/null +++ b/internal/stacks/stackruntime/testdata/mainbundle/test/state-manipulation/deferred/ok/ok.tf @@ -0,0 +1,13 @@ +terraform { + required_providers { + testing = { + source = "hashicorp/testing" + version = "0.1.0" + } + } +} + +resource "testing_resource" "self" { + id = "ok" + value = "ok" +}