diff --git a/internal/addrs/resource.go b/internal/addrs/resource.go index da6e774c60..2e0d1271d0 100644 --- a/internal/addrs/resource.go +++ b/internal/addrs/resource.go @@ -4,8 +4,11 @@ package addrs import ( + "encoding/hex" "fmt" + "math/rand" "strings" + "time" ) // Resource is an address for a resource block within configuration, which @@ -292,6 +295,26 @@ func (r AbsResourceInstance) ConfigResource() ConfigResource { } } +// CurrentObject returns the address of the resource instance's "current" +// object, which is the one used for expression evaluation etc. +func (r AbsResourceInstance) CurrentObject() AbsResourceInstanceObject { + return AbsResourceInstanceObject{ + ResourceInstance: r, + DeposedKey: NotDeposed, + } +} + +// DeposedObject returns the address of a "deposed" object for the receiving +// resource instance, which appears only if a create-before-destroy replacement +// succeeds the create step but fails the destroy step, making the original +// object live on as a desposed object. +func (r AbsResourceInstance) DeposedObject(key DeposedKey) AbsResourceInstanceObject { + return AbsResourceInstanceObject{ + ResourceInstance: r, + DeposedKey: key, + } +} + // TargetContains implements Targetable by returning true if the given other // address is equal to the receiver. func (r AbsResourceInstance) TargetContains(other Targetable) bool { @@ -480,3 +503,107 @@ const ( // "data" blocks in configuration. DataResourceMode ResourceMode = 'D' ) + +// AbsResourceInstanceObject represents one of the specific remote objects +// associated with a resource instance. +// +// When DeposedKey is [NotDeposed], this represents the "current" object. +// Otherwise, this represents a deposed object with the given key. +// +// The distinction between "current" and "deposed" objects is a planning and +// state concern that isn't reflected directly in configuration, so there +// are no "ConfigResourceInstanceObject" or "ResourceInstanceObject" address +// types. +type AbsResourceInstanceObject struct { + ResourceInstance AbsResourceInstance + DeposedKey DeposedKey +} + +// String returns a string that could be used to refer to this object +// in the UI, but is not necessarily suitable for use as a unique key. +func (o AbsResourceInstanceObject) String() string { + if o.DeposedKey != NotDeposed { + return fmt.Sprintf("%s deposed object %s", o.ResourceInstance, o.DeposedKey) + } + return o.ResourceInstance.String() +} + +// IsCurrent returns true only if this address is for a "current" object. +func (o AbsResourceInstanceObject) IsCurrent() bool { + return o.DeposedKey == NotDeposed +} + +// IsCurrent returns true only if this address is for a "deposed" object. +func (o AbsResourceInstanceObject) IsDeposed() bool { + return o.DeposedKey != NotDeposed +} + +// UniqueKey implements [UniqueKeyer] +func (o AbsResourceInstanceObject) UniqueKey() UniqueKey { + return absResourceInstanceObjectKey{ + resourceInstanceKey: o.ResourceInstance.UniqueKey(), + deposedKey: o.DeposedKey, + } +} + +type absResourceInstanceObjectKey struct { + resourceInstanceKey UniqueKey + deposedKey DeposedKey +} + +func (absResourceInstanceObjectKey) uniqueKeySigil() {} + +// DeposedKey is a 8-character hex string used to uniquely identify deposed +// instance objects in the state. +// +// The zero value of this type is [NotDeposed] and represents a "current" +// object, not deposed at all. All other valid values of this type are strings +// containing exactly eight lowercase hex characters. +type DeposedKey string + +// NotDeposed is a special invalid value of DeposedKey that is used to represent +// the absense of a deposed key, typically when referring to the "current" object +// for a particular resource instance. It must not be used as an actual deposed +// key. +const NotDeposed = DeposedKey("") + +var deposedKeyRand = rand.New(rand.NewSource(time.Now().UnixNano())) + +// NewDeposedKey generates a pseudo-random deposed key. Because of the short +// length of these keys, uniqueness is not a natural consequence and so the +// caller should test to see if the generated key is already in use and generate +// another if so, until a unique key is found. +func NewDeposedKey() DeposedKey { + v := deposedKeyRand.Uint32() + return DeposedKey(fmt.Sprintf("%08x", v)) +} + +// ParseDeposedKey parses a string that is expected to be a deposed key, +// returning an error if it doesn't conform to the expected syntax. +func ParseDeposedKey(raw string) (DeposedKey, error) { + if len(raw) != 8 { + return "00000000", fmt.Errorf("must be eight hexadecimal digits") + } + if raw != strings.ToLower(raw) { + return "00000000", fmt.Errorf("must use lowercase hex digits") + } + _, err := hex.DecodeString(raw) + if err != nil { + return "00000000", fmt.Errorf("must be eight hexadecimal digits") + } + return DeposedKey(raw), nil +} + +func (k DeposedKey) String() string { + return string(k) +} + +func (k DeposedKey) GoString() string { + ks := string(k) + switch { + case ks == "": + return "states.NotDeposed" + default: + return fmt.Sprintf("states.DeposedKey(%q)", ks) + } +} diff --git a/internal/command/views/hook_count.go b/internal/command/views/hook_count.go index cff1ef819e..dd9dd5408e 100644 --- a/internal/command/views/hook_count.go +++ b/internal/command/views/hook_count.go @@ -10,7 +10,6 @@ import ( "github.com/hashicorp/terraform/internal/addrs" "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" "github.com/hashicorp/terraform/internal/terraform" ) @@ -46,7 +45,7 @@ func (h *countHook) Reset() { h.Imported = 0 } -func (h *countHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (terraform.HookAction, error) { +func (h *countHook) PreApply(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, action plans.Action, priorState, plannedNewState cty.Value) (terraform.HookAction, error) { h.Lock() defer h.Unlock() @@ -59,7 +58,7 @@ func (h *countHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generati return terraform.HookActionContinue, nil } -func (h *countHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (terraform.HookAction, error) { +func (h *countHook) PostApply(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, newState cty.Value, err error) (terraform.HookAction, error) { h.Lock() defer h.Unlock() @@ -87,7 +86,7 @@ func (h *countHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generat return terraform.HookActionContinue, nil } -func (h *countHook) PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (terraform.HookAction, error) { +func (h *countHook) PostDiff(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, action plans.Action, priorState, plannedNewState cty.Value) (terraform.HookAction, error) { h.Lock() defer h.Unlock() diff --git a/internal/command/views/hook_count_test.go b/internal/command/views/hook_count_test.go index b29abd6d3e..0706d84a6e 100644 --- a/internal/command/views/hook_count_test.go +++ b/internal/command/views/hook_count_test.go @@ -66,7 +66,7 @@ func TestCountHookPostDiff_DestroyOnly(t *testing.T) { Name: k, }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance) - h.PostDiff(addr, states.CurrentGen, plans.Delete, cty.DynamicVal, cty.DynamicVal) + h.PostDiff(addr, addrs.NotDeposed, plans.Delete, cty.DynamicVal, cty.DynamicVal) } expected := new(countHook) @@ -108,7 +108,7 @@ func TestCountHookPostDiff_AddOnly(t *testing.T) { Name: k, }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance) - h.PostDiff(addr, states.CurrentGen, plans.Create, cty.DynamicVal, cty.DynamicVal) + h.PostDiff(addr, addrs.NotDeposed, plans.Create, cty.DynamicVal, cty.DynamicVal) } expected := new(countHook) @@ -153,7 +153,7 @@ func TestCountHookPostDiff_ChangeOnly(t *testing.T) { Name: k, }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance) - h.PostDiff(addr, states.CurrentGen, plans.Update, cty.DynamicVal, cty.DynamicVal) + h.PostDiff(addr, addrs.NotDeposed, plans.Update, cty.DynamicVal, cty.DynamicVal) } expected := new(countHook) @@ -184,7 +184,7 @@ func TestCountHookPostDiff_Mixed(t *testing.T) { Name: k, }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance) - h.PostDiff(addr, states.CurrentGen, a, cty.DynamicVal, cty.DynamicVal) + h.PostDiff(addr, addrs.NotDeposed, a, cty.DynamicVal, cty.DynamicVal) } expected := new(countHook) @@ -216,7 +216,7 @@ func TestCountHookPostDiff_NoChange(t *testing.T) { Name: k, }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance) - h.PostDiff(addr, states.CurrentGen, plans.NoOp, cty.DynamicVal, cty.DynamicVal) + h.PostDiff(addr, addrs.NotDeposed, plans.NoOp, cty.DynamicVal, cty.DynamicVal) } expected := new(countHook) @@ -248,7 +248,7 @@ func TestCountHookPostDiff_DataSource(t *testing.T) { Name: k, }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance) - h.PostDiff(addr, states.CurrentGen, a, cty.DynamicVal, cty.DynamicVal) + h.PostDiff(addr, addrs.NotDeposed, a, cty.DynamicVal, cty.DynamicVal) } expected := new(countHook) @@ -294,8 +294,8 @@ func TestCountHookApply_ChangeOnly(t *testing.T) { Name: k, }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance) - h.PreApply(addr, states.CurrentGen, plans.Update, cty.DynamicVal, cty.DynamicVal) - h.PostApply(addr, states.CurrentGen, cty.DynamicVal, nil) + h.PreApply(addr, addrs.NotDeposed, plans.Update, cty.DynamicVal, cty.DynamicVal) + h.PostApply(addr, addrs.NotDeposed, cty.DynamicVal, nil) } expected := &countHook{pending: make(map[string]plans.Action)} @@ -325,8 +325,8 @@ func TestCountHookApply_DestroyOnly(t *testing.T) { Name: k, }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance) - h.PreApply(addr, states.CurrentGen, plans.Delete, cty.DynamicVal, cty.DynamicVal) - h.PostApply(addr, states.CurrentGen, cty.DynamicVal, nil) + h.PreApply(addr, addrs.NotDeposed, plans.Delete, cty.DynamicVal, cty.DynamicVal) + h.PostApply(addr, addrs.NotDeposed, cty.DynamicVal, nil) } expected := &countHook{pending: make(map[string]plans.Action)} diff --git a/internal/command/views/hook_json.go b/internal/command/views/hook_json.go index 9758e537e1..f9076f61e5 100644 --- a/internal/command/views/hook_json.go +++ b/internal/command/views/hook_json.go @@ -16,7 +16,6 @@ import ( "github.com/hashicorp/terraform/internal/command/format" "github.com/hashicorp/terraform/internal/command/views/json" "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" "github.com/hashicorp/terraform/internal/terraform" ) @@ -62,7 +61,7 @@ type applyProgress struct { heartbeatDone chan struct{} } -func (h *jsonHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (terraform.HookAction, error) { +func (h *jsonHook) PreApply(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, action plans.Action, priorState, plannedNewState cty.Value) (terraform.HookAction, error) { if action != plans.NoOp { idKey, idValue := format.ObjectValueIDOrName(priorState) h.view.Hook(json.NewApplyStart(addr, action, idKey, idValue)) @@ -99,7 +98,7 @@ func (h *jsonHook) applyingHeartbeat(progress applyProgress) { } } -func (h *jsonHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (terraform.HookAction, error) { +func (h *jsonHook) PostApply(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, newState cty.Value, err error) (terraform.HookAction, error) { key := addr.String() h.applyingLock.Lock() progress := h.applying[key] @@ -155,13 +154,13 @@ func (h *jsonHook) ProvisionOutput(addr addrs.AbsResourceInstance, typeName stri } } -func (h *jsonHook) PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (terraform.HookAction, error) { +func (h *jsonHook) PreRefresh(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, priorState cty.Value) (terraform.HookAction, error) { idKey, idValue := format.ObjectValueID(priorState) h.view.Hook(json.NewRefreshStart(addr, idKey, idValue)) return terraform.HookActionContinue, nil } -func (h *jsonHook) PostRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value, newState cty.Value) (terraform.HookAction, error) { +func (h *jsonHook) PostRefresh(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, priorState cty.Value, newState cty.Value) (terraform.HookAction, error) { idKey, idValue := format.ObjectValueID(newState) h.view.Hook(json.NewRefreshComplete(addr, idKey, idValue)) return terraform.HookActionContinue, nil diff --git a/internal/command/views/hook_json_test.go b/internal/command/views/hook_json_test.go index 279fa799d4..b0c3732e71 100644 --- a/internal/command/views/hook_json_test.go +++ b/internal/command/views/hook_json_test.go @@ -11,7 +11,6 @@ import ( "github.com/hashicorp/terraform/internal/addrs" "github.com/hashicorp/terraform/internal/plans" - "github.com/hashicorp/terraform/internal/states" "github.com/hashicorp/terraform/internal/terminal" "github.com/hashicorp/terraform/internal/terraform" "github.com/zclconf/go-cty/cty" @@ -49,7 +48,7 @@ func TestJSONHook_create(t *testing.T) { }), }) - action, err := hook.PreApply(addr, states.CurrentGen, plans.Create, priorState, plannedNewState) + action, err := hook.PreApply(addr, addrs.NotDeposed, plans.Create, priorState, plannedNewState) testHookReturnValues(t, action, err) action, err = hook.PreProvisionInstanceStep(addr, "local-exec") @@ -81,7 +80,7 @@ func TestJSONHook_create(t *testing.T) { now = now.Add(2 * time.Second) nowMu.Unlock() - action, err = hook.PostApply(addr, states.CurrentGen, plannedNewState, nil) + action, err = hook.PostApply(addr, addrs.NotDeposed, plannedNewState, nil) testHookReturnValues(t, action, err) // Shut down the progress goroutine if still active @@ -204,7 +203,7 @@ func TestJSONHook_errors(t *testing.T) { }), }) - action, err := hook.PreApply(addr, states.CurrentGen, plans.Delete, priorState, plannedNewState) + action, err := hook.PreApply(addr, addrs.NotDeposed, plans.Delete, priorState, plannedNewState) testHookReturnValues(t, action, err) provisionError := fmt.Errorf("provisioner didn't want to") @@ -212,7 +211,7 @@ func TestJSONHook_errors(t *testing.T) { testHookReturnValues(t, action, err) applyError := fmt.Errorf("provider was sad") - action, err = hook.PostApply(addr, states.CurrentGen, plannedNewState, applyError) + action, err = hook.PostApply(addr, addrs.NotDeposed, plannedNewState, applyError) testHookReturnValues(t, action, err) // Shut down the progress goroutine @@ -286,10 +285,10 @@ func TestJSONHook_refresh(t *testing.T) { }), }) - action, err := hook.PreRefresh(addr, states.CurrentGen, state) + action, err := hook.PreRefresh(addr, addrs.NotDeposed, state) testHookReturnValues(t, action, err) - action, err = hook.PostRefresh(addr, states.CurrentGen, state, state) + action, err = hook.PostRefresh(addr, addrs.NotDeposed, state, state) testHookReturnValues(t, action, err) wantResource := map[string]interface{}{ diff --git a/internal/command/views/hook_ui.go b/internal/command/views/hook_ui.go index c169031ba0..e9771ad1c3 100644 --- a/internal/command/views/hook_ui.go +++ b/internal/command/views/hook_ui.go @@ -18,7 +18,6 @@ import ( "github.com/hashicorp/terraform/internal/command/format" "github.com/hashicorp/terraform/internal/plans" "github.com/hashicorp/terraform/internal/providers" - "github.com/hashicorp/terraform/internal/states" "github.com/hashicorp/terraform/internal/terraform" ) @@ -71,10 +70,10 @@ const ( uiResourceNoOp ) -func (h *UiHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (terraform.HookAction, error) { +func (h *UiHook) PreApply(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, action plans.Action, priorState, plannedNewState cty.Value) (terraform.HookAction, error) { dispAddr := addr.String() - if gen != states.CurrentGen { - dispAddr = fmt.Sprintf("%s (deposed object %s)", dispAddr, gen) + if dk != addrs.NotDeposed { + dispAddr = fmt.Sprintf("%s (deposed object %s)", dispAddr, dk) } var operation string @@ -184,7 +183,7 @@ func (h *UiHook) stillApplying(state uiResourceState) { } } -func (h *UiHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, applyerr error) (terraform.HookAction, error) { +func (h *UiHook) PostApply(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, newState cty.Value, applyerr error) (terraform.HookAction, error) { id := addr.String() h.resourcesLock.Lock() @@ -224,8 +223,8 @@ func (h *UiHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation } addrStr := addr.String() - if depKey, ok := gen.(states.DeposedKey); ok { - addrStr = fmt.Sprintf("%s (deposed object %s)", addrStr, depKey) + if dk != addrs.NotDeposed { + addrStr = fmt.Sprintf("%s (deposed object %s)", addrStr, dk) } colorized := fmt.Sprintf( @@ -264,15 +263,15 @@ func (h *UiHook) ProvisionOutput(addr addrs.AbsResourceInstance, typeName string h.println(strings.TrimSpace(buf.String())) } -func (h *UiHook) PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (terraform.HookAction, error) { +func (h *UiHook) PreRefresh(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, priorState cty.Value) (terraform.HookAction, error) { var stateIdSuffix string if k, v := format.ObjectValueID(priorState); k != "" && v != "" { stateIdSuffix = fmt.Sprintf(" [%s=%s]", k, v) } addrStr := addr.String() - if depKey, ok := gen.(states.DeposedKey); ok { - addrStr = fmt.Sprintf("%s (deposed object %s)", addrStr, depKey) + if dk != addrs.NotDeposed { + addrStr = fmt.Sprintf("%s (deposed object %s)", addrStr, dk) } h.println(fmt.Sprintf( diff --git a/internal/command/views/hook_ui_test.go b/internal/command/views/hook_ui_test.go index bc4789a4ac..badfb501cd 100644 --- a/internal/command/views/hook_ui_test.go +++ b/internal/command/views/hook_ui_test.go @@ -51,7 +51,7 @@ func TestUiHookPreApply_create(t *testing.T) { }), }) - action, err := h.PreApply(addr, states.CurrentGen, plans.Create, priorState, plannedNewState) + action, err := h.PreApply(addr, addrs.NotDeposed, plans.Create, priorState, plannedNewState) if err != nil { t.Fatal(err) } @@ -109,7 +109,7 @@ func TestUiHookPreApply_periodicTimer(t *testing.T) { }), }) - action, err := h.PreApply(addr, states.CurrentGen, plans.Update, priorState, plannedNewState) + action, err := h.PreApply(addr, addrs.NotDeposed, plans.Update, priorState, plannedNewState) if err != nil { t.Fatal(err) } @@ -224,7 +224,7 @@ func TestUiHookPostApply_colorInterpolation(t *testing.T) { "id": cty.StringVal("[blue]"), }) - action, err := h.PostApply(addr, states.CurrentGen, newState, nil) + action, err := h.PostApply(addr, addrs.NotDeposed, newState, nil) if err != nil { t.Fatal(err) } @@ -277,7 +277,7 @@ func TestUiHookPostApply_emptyState(t *testing.T) { "names": cty.List(cty.String), })) - action, err := h.PostApply(addr, states.CurrentGen, newState, nil) + action, err := h.PostApply(addr, addrs.NotDeposed, newState, nil) if err != nil { t.Fatal(err) } @@ -425,7 +425,7 @@ func TestPreRefresh(t *testing.T) { "bar": cty.ListValEmpty(cty.String), }) - action, err := h.PreRefresh(addr, states.CurrentGen, priorState) + action, err := h.PreRefresh(addr, addrs.NotDeposed, priorState) if err != nil { t.Fatal(err) @@ -457,7 +457,7 @@ func TestPreRefresh_noID(t *testing.T) { "bar": cty.ListValEmpty(cty.String), }) - action, err := h.PreRefresh(addr, states.CurrentGen, priorState) + action, err := h.PreRefresh(addr, addrs.NotDeposed, priorState) if err != nil { t.Fatal(err) diff --git a/internal/plans/changes_sync.go b/internal/plans/changes_sync.go index 61bc1c65c9..67e7502763 100644 --- a/internal/plans/changes_sync.go +++ b/internal/plans/changes_sync.go @@ -4,11 +4,9 @@ package plans import ( - "fmt" "sync" "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/states" ) // ChangesSync is a wrapper around a Changes that provides a concurrency-safe @@ -42,27 +40,26 @@ func (cs *ChangesSync) AppendResourceInstanceChange(changeSrc *ResourceInstanceC } // GetResourceInstanceChange searches the set of resource instance changes for -// one matching the given address and generation, returning it if it exists. +// one matching the given address and deposed key, returning it if it exists. +// Use [addrs.NotDeposed] as the deposed key to represent the "current" +// object for the given resource instance. // // If no such change exists, nil is returned. // // The returned object is a deep copy of the change recorded in the plan, so // callers may mutate it although it's generally better (less confusing) to // treat planned changes as immutable after they've been initially constructed. -func (cs *ChangesSync) GetResourceInstanceChange(addr addrs.AbsResourceInstance, gen states.Generation) *ResourceInstanceChangeSrc { +func (cs *ChangesSync) GetResourceInstanceChange(addr addrs.AbsResourceInstance, dk addrs.DeposedKey) *ResourceInstanceChangeSrc { if cs == nil { panic("GetResourceInstanceChange on nil ChangesSync") } cs.lock.Lock() defer cs.lock.Unlock() - if gen == states.CurrentGen { + if dk == addrs.NotDeposed { return cs.changes.ResourceInstance(addr).DeepCopy() } - if dk, ok := gen.(states.DeposedKey); ok { - return cs.changes.ResourceInstanceDeposed(addr, dk).DeepCopy() - } - panic(fmt.Sprintf("unsupported generation value %#v", gen)) + return cs.changes.ResourceInstanceDeposed(addr, dk).DeepCopy() } // GetChangesForConfigResource searches the set of resource instance @@ -110,20 +107,15 @@ func (cs *ChangesSync) GetChangesForAbsResource(addr addrs.AbsResource) []*Resou } // RemoveResourceInstanceChange searches the set of resource instance changes -// for one matching the given address and generation, and removes it from the +// for one matching the given address and deposed key, and removes it from the // set if it exists. -func (cs *ChangesSync) RemoveResourceInstanceChange(addr addrs.AbsResourceInstance, gen states.Generation) { +func (cs *ChangesSync) RemoveResourceInstanceChange(addr addrs.AbsResourceInstance, dk addrs.DeposedKey) { if cs == nil { panic("RemoveResourceInstanceChange on nil ChangesSync") } cs.lock.Lock() defer cs.lock.Unlock() - dk := states.NotDeposed - if realDK, ok := gen.(states.DeposedKey); ok { - dk = realDK - } - addrStr := addr.String() for i, r := range cs.changes.Resources { if r.Addr.String() != addrStr || r.DeposedKey != dk { diff --git a/internal/stacks/stackruntime/internal/stackeval/terraform_hook.go b/internal/stacks/stackruntime/internal/stackeval/terraform_hook.go index ce7ac0340f..5be60d1c91 100644 --- a/internal/stacks/stackruntime/internal/stackeval/terraform_hook.go +++ b/internal/stacks/stackruntime/internal/stackeval/terraform_hook.go @@ -10,7 +10,6 @@ import ( "github.com/hashicorp/terraform/internal/plans" "github.com/hashicorp/terraform/internal/stacks/stackaddrs" "github.com/hashicorp/terraform/internal/stacks/stackruntime/hooks" - "github.com/hashicorp/terraform/internal/states" "github.com/hashicorp/terraform/internal/terraform" "github.com/zclconf/go-cty/cty" ) @@ -39,7 +38,7 @@ func (h *componentInstanceTerraformHook) resourceInstanceAddr(addr addrs.AbsReso } } -func (h *componentInstanceTerraformHook) PreDiff(addr addrs.AbsResourceInstance, gen states.Generation, priorState, proposedNewState cty.Value) (terraform.HookAction, error) { +func (h *componentInstanceTerraformHook) PreDiff(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, priorState, proposedNewState cty.Value) (terraform.HookAction, error) { hookMore(h.ctx, h.seq, h.hooks.ReportResourceInstanceStatus, &hooks.ResourceInstanceStatusHookData{ Addr: h.resourceInstanceAddr(addr), Status: hooks.ResourceInstancePlanning, @@ -47,7 +46,7 @@ func (h *componentInstanceTerraformHook) PreDiff(addr addrs.AbsResourceInstance, return terraform.HookActionContinue, nil } -func (h *componentInstanceTerraformHook) PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (terraform.HookAction, error) { +func (h *componentInstanceTerraformHook) PostDiff(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, action plans.Action, priorState, plannedNewState cty.Value) (terraform.HookAction, error) { hookMore(h.ctx, h.seq, h.hooks.ReportResourceInstanceStatus, &hooks.ResourceInstanceStatusHookData{ Addr: h.resourceInstanceAddr(addr), Status: hooks.ResourceInstancePlanned, @@ -55,7 +54,7 @@ func (h *componentInstanceTerraformHook) PostDiff(addr addrs.AbsResourceInstance return terraform.HookActionContinue, nil } -func (h *componentInstanceTerraformHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (terraform.HookAction, error) { +func (h *componentInstanceTerraformHook) PreApply(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, action plans.Action, priorState, plannedNewState cty.Value) (terraform.HookAction, error) { if action != plans.NoOp { hookMore(h.ctx, h.seq, h.hooks.ReportResourceInstanceStatus, &hooks.ResourceInstanceStatusHookData{ Addr: h.resourceInstanceAddr(addr), @@ -65,7 +64,7 @@ func (h *componentInstanceTerraformHook) PreApply(addr addrs.AbsResourceInstance return terraform.HookActionContinue, nil } -func (h *componentInstanceTerraformHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (terraform.HookAction, error) { +func (h *componentInstanceTerraformHook) PostApply(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, newState cty.Value, err error) (terraform.HookAction, error) { // FIXME: need to emit nothing if this was a no-op, which means tracking // the `action` argument to `PreApply`. See `jsonHook` for more on this. status := hooks.ResourceInstanceApplied diff --git a/internal/states/instance_generation.go b/internal/states/instance_generation.go deleted file mode 100644 index 888ff890f2..0000000000 --- a/internal/states/instance_generation.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -package states - -// Generation is used to represent multiple objects in a succession of objects -// represented by a single resource instance address. A resource instance can -// have multiple generations over its lifetime due to object replacement -// (when a change can't be applied without destroying and re-creating), and -// multiple generations can exist at the same time when create_before_destroy -// is used. -// -// A Generation value can either be the value of the variable "CurrentGen" or -// a value of type DeposedKey. Generation values can be compared for equality -// using "==" and used as map keys. The zero value of Generation (nil) is not -// a valid generation and must not be used. -type Generation interface { - generation() -} - -// CurrentGen is the Generation representing the currently-active object for -// a resource instance. -var CurrentGen Generation diff --git a/internal/states/resource.go b/internal/states/resource.go index 8eb9c5e8da..25eed13c5e 100644 --- a/internal/states/resource.go +++ b/internal/states/resource.go @@ -4,11 +4,7 @@ package states import ( - "encoding/hex" "fmt" - "math/rand" - "strings" - "time" "github.com/hashicorp/terraform/internal/addrs" ) @@ -128,23 +124,14 @@ func (i *ResourceInstance) deposeCurrentObject(forceKey DeposedKey) DeposedKey { return key } -// GetGeneration retrieves the object of the given generation from the -// ResourceInstance, or returns nil if there is no such object. -// -// If the given generation is nil or invalid, this method will panic. -func (i *ResourceInstance) GetGeneration(gen Generation) *ResourceInstanceObjectSrc { - if gen == CurrentGen { +// Object retrieves the object with the given deposed key from the +// ResourceInstance, or returns nil if there is no such object. Use +// [addrs.NotDeposed] to retrieve the "current" object, if any. +func (i *ResourceInstance) Object(dk DeposedKey) *ResourceInstanceObjectSrc { + if dk == addrs.NotDeposed { return i.Current } - if dk, ok := gen.(DeposedKey); ok { - return i.Deposed[dk] - } - if gen == nil { - panic("get with nil Generation") - } - // Should never fall out here, since the above covers all possible - // Generation values. - panic(fmt.Sprintf("get invalid Generation %#v", gen)) + return i.Deposed[dk] } // FindUnusedDeposedKey generates a unique DeposedKey that is guaranteed not to @@ -172,65 +159,21 @@ func (i *ResourceInstance) findUnusedDeposedKey() DeposedKey { } } -// DeposedKey is a 8-character hex string used to uniquely identify deposed -// instance objects in the state. -type DeposedKey string - -// NotDeposed is a special invalid value of DeposedKey that is used to represent -// the absense of a deposed key. It must not be used as an actual deposed key. -const NotDeposed = DeposedKey("") +// DeposedKey is an alias for [addrs.DeposedKey], representing keys assigned +// to deposed resource instance objects. +type DeposedKey = addrs.DeposedKey -var deposedKeyRand = rand.New(rand.NewSource(time.Now().UnixNano())) +// NotDeposed is an alias for the zero value of [addrs.DeposedKey], which +// represents the absense of a deposed key, i.e. that the associated object +// is the "current" object for some resource instance. +const NotDeposed = addrs.NotDeposed -// NewDeposedKey generates a pseudo-random deposed key. Because of the short -// length of these keys, uniqueness is not a natural consequence and so the -// caller should test to see if the generated key is already in use and generate -// another if so, until a unique key is found. +// NewDeposedKey is an alias for [addrs.NewDeposedKey]. func NewDeposedKey() DeposedKey { - v := deposedKeyRand.Uint32() - return DeposedKey(fmt.Sprintf("%08x", v)) + return addrs.NewDeposedKey() } -// ParseDeposedKey parses a string that is expected to be a deposed key, -// returning an error if it doesn't conform to the expected syntax. +// ParseDeposedKey is an alias for [addrs.ParseDeposedKey]. func ParseDeposedKey(raw string) (DeposedKey, error) { - if len(raw) != 8 { - return "00000000", fmt.Errorf("must be eight hexadecimal digits") - } - if raw != strings.ToLower(raw) { - return "00000000", fmt.Errorf("must use lowercase hex digits") - } - _, err := hex.DecodeString(raw) - if err != nil { - return "00000000", fmt.Errorf("must be eight hexadecimal digits") - } - return DeposedKey(raw), nil -} - -func (k DeposedKey) String() string { - return string(k) -} - -func (k DeposedKey) GoString() string { - ks := string(k) - switch { - case ks == "": - return "states.NotDeposed" - default: - return fmt.Sprintf("states.DeposedKey(%s)", ks) - } + return addrs.ParseDeposedKey(raw) } - -// Generation is a helper method to convert a DeposedKey into a Generation. -// If the reciever is anything other than NotDeposed then the result is -// just the same value as a Generation. If the receiver is NotDeposed then -// the result is CurrentGen. -func (k DeposedKey) Generation() Generation { - if k == NotDeposed { - return CurrentGen - } - return k -} - -// generation is an implementation of Generation. -func (k DeposedKey) generation() {} diff --git a/internal/states/sync.go b/internal/states/sync.go index 3266a1ea77..b82af1c10f 100644 --- a/internal/states/sync.go +++ b/internal/states/sync.go @@ -181,13 +181,14 @@ func (s *SyncState) ResourceInstance(addr addrs.AbsResourceInstance) *ResourceIn return ret } -// ResourceInstanceObject returns a snapshot of the current instance object -// of the given generation belonging to the instance with the given address, -// or nil if no such object is tracked.. +// ResourceInstanceObject returns a snapshot of the resource instance object +// of the given deposed key belonging to the given resource instance. Use +// [addrs.NotDeposed] for the deposed key to retrieve the "current" object, +// if any. Returns nil if there is no such object. // // The return value is a pointer to a copy of the object, which the caller may // then freely access and mutate. -func (s *SyncState) ResourceInstanceObject(addr addrs.AbsResourceInstance, gen Generation) *ResourceInstanceObjectSrc { +func (s *SyncState) ResourceInstanceObject(addr addrs.AbsResourceInstance, dk DeposedKey) *ResourceInstanceObjectSrc { s.lock.RLock() defer s.lock.RUnlock() @@ -195,7 +196,7 @@ func (s *SyncState) ResourceInstanceObject(addr addrs.AbsResourceInstance, gen G if inst == nil { return nil } - return inst.GetGeneration(gen).DeepCopy() + return inst.Object(dk).DeepCopy() } // SetResourceMeta updates the resource-level metadata for the resource at diff --git a/internal/terraform/context_apply_test.go b/internal/terraform/context_apply_test.go index 718c988691..977faa8192 100644 --- a/internal/terraform/context_apply_test.go +++ b/internal/terraform/context_apply_test.go @@ -1135,7 +1135,7 @@ func TestContext2Apply_createBeforeDestroy_hook(t *testing.T) { var actual []cty.Value var actualLock sync.Mutex - h.PostApplyFn = func(addr addrs.AbsResourceInstance, gen states.Generation, sv cty.Value, e error) (HookAction, error) { + h.PostApplyFn = func(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, sv cty.Value, e error) (HookAction, error) { actualLock.Lock() defer actualLock.Unlock() diff --git a/internal/terraform/eval_context_builtin.go b/internal/terraform/eval_context_builtin.go index 7e64d9f7f5..ccd30f9929 100644 --- a/internal/terraform/eval_context_builtin.go +++ b/internal/terraform/eval_context_builtin.go @@ -331,7 +331,7 @@ func (ctx *BuiltinEvalContext) EvaluateReplaceTriggeredBy(expr hcl.Expression, r case addrs.ResourceInstance: resourceAddr = sub.ContainingResource() rc := sub.Absolute(ctx.Path()) - change := ctx.Changes().GetResourceInstanceChange(rc, states.CurrentGen) + change := ctx.Changes().GetResourceInstanceChange(rc, addrs.NotDeposed) if change != nil { // we'll generate an error below if there was no change changes = append(changes, change) diff --git a/internal/terraform/evaluate.go b/internal/terraform/evaluate.go index 622083263e..8cf9fe771e 100644 --- a/internal/terraform/evaluate.go +++ b/internal/terraform/evaluate.go @@ -755,7 +755,7 @@ func (d *evaluationStateData) GetResource(addr addrs.Resource, rng tfdiags.Sourc instAddr := addr.Instance(key).Absolute(d.ModulePath) - change := d.Evaluator.Changes.GetResourceInstanceChange(instAddr, states.CurrentGen) + change := d.Evaluator.Changes.GetResourceInstanceChange(instAddr, addrs.NotDeposed) if change != nil { // Don't take any resources that are yet to be deleted into account. // If the referenced resource is CreateBeforeDestroy, then orphaned diff --git a/internal/terraform/hook.go b/internal/terraform/hook.go index a09a82f9f6..49acfb1540 100644 --- a/internal/terraform/hook.go +++ b/internal/terraform/hook.go @@ -36,14 +36,14 @@ type Hook interface { // PreApply and PostApply are called before and after an action for a // single instance is applied. The error argument in PostApply is the // error, if any, that was returned from the provider Apply call itself. - PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) - PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (HookAction, error) + PreApply(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) + PostApply(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, newState cty.Value, err error) (HookAction, error) // PreDiff and PostDiff are called before and after a provider is given // the opportunity to customize the proposed new state to produce the // planned new state. - PreDiff(addr addrs.AbsResourceInstance, gen states.Generation, priorState, proposedNewState cty.Value) (HookAction, error) - PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) + PreDiff(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, priorState, proposedNewState cty.Value) (HookAction, error) + PostDiff(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) // The provisioning hooks signal both the overall start end end of // provisioning for a particular instance and of each of the individual @@ -71,8 +71,8 @@ type Hook interface { // PreRefresh and PostRefresh are called before and after a single // resource state is refreshed, respectively. - PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (HookAction, error) - PostRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value, newState cty.Value) (HookAction, error) + PreRefresh(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, priorState cty.Value) (HookAction, error) + PostRefresh(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, priorState cty.Value, newState cty.Value) (HookAction, error) // PreImportState and PostImportState are called before and after // (respectively) each state import operation for a given resource address when @@ -119,19 +119,19 @@ type NilHook struct{} var _ Hook = (*NilHook)(nil) -func (*NilHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { +func (*NilHook) PreApply(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { return HookActionContinue, nil } -func (*NilHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (HookAction, error) { +func (*NilHook) PostApply(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, newState cty.Value, err error) (HookAction, error) { return HookActionContinue, nil } -func (*NilHook) PreDiff(addr addrs.AbsResourceInstance, gen states.Generation, priorState, proposedNewState cty.Value) (HookAction, error) { +func (*NilHook) PreDiff(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, priorState, proposedNewState cty.Value) (HookAction, error) { return HookActionContinue, nil } -func (*NilHook) PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { +func (*NilHook) PostDiff(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { return HookActionContinue, nil } @@ -154,11 +154,11 @@ func (*NilHook) PostProvisionInstanceStep(addr addrs.AbsResourceInstance, typeNa func (*NilHook) ProvisionOutput(addr addrs.AbsResourceInstance, typeName string, line string) { } -func (*NilHook) PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (HookAction, error) { +func (*NilHook) PreRefresh(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, priorState cty.Value) (HookAction, error) { return HookActionContinue, nil } -func (*NilHook) PostRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value, newState cty.Value) (HookAction, error) { +func (*NilHook) PostRefresh(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, priorState cty.Value, newState cty.Value) (HookAction, error) { return HookActionContinue, nil } diff --git a/internal/terraform/hook_mock.go b/internal/terraform/hook_mock.go index ba727ba7d7..1fa9155b07 100644 --- a/internal/terraform/hook_mock.go +++ b/internal/terraform/hook_mock.go @@ -21,7 +21,7 @@ type MockHook struct { PreApplyCalled bool PreApplyAddr addrs.AbsResourceInstance - PreApplyGen states.Generation + PreApplyGen addrs.DeposedKey PreApplyAction plans.Action PreApplyPriorState cty.Value PreApplyPlannedState cty.Value @@ -30,16 +30,16 @@ type MockHook struct { PostApplyCalled bool PostApplyAddr addrs.AbsResourceInstance - PostApplyGen states.Generation + PostApplyGen addrs.DeposedKey PostApplyNewState cty.Value PostApplyError error PostApplyReturn HookAction PostApplyReturnError error - PostApplyFn func(addrs.AbsResourceInstance, states.Generation, cty.Value, error) (HookAction, error) + PostApplyFn func(addrs.AbsResourceInstance, addrs.DeposedKey, cty.Value, error) (HookAction, error) PreDiffCalled bool PreDiffAddr addrs.AbsResourceInstance - PreDiffGen states.Generation + PreDiffGen addrs.DeposedKey PreDiffPriorState cty.Value PreDiffProposedState cty.Value PreDiffReturn HookAction @@ -47,7 +47,7 @@ type MockHook struct { PostDiffCalled bool PostDiffAddr addrs.AbsResourceInstance - PostDiffGen states.Generation + PostDiffGen addrs.DeposedKey PostDiffAction plans.Action PostDiffPriorState cty.Value PostDiffPlannedState cty.Value @@ -86,14 +86,14 @@ type MockHook struct { PreRefreshCalled bool PreRefreshAddr addrs.AbsResourceInstance - PreRefreshGen states.Generation + PreRefreshGen addrs.DeposedKey PreRefreshPriorState cty.Value PreRefreshReturn HookAction PreRefreshError error PostRefreshCalled bool PostRefreshAddr addrs.AbsResourceInstance - PostRefreshGen states.Generation + PostRefreshGen addrs.DeposedKey PostRefreshPriorState cty.Value PostRefreshNewState cty.Value PostRefreshReturn HookAction @@ -141,55 +141,55 @@ type MockHook struct { var _ Hook = (*MockHook)(nil) -func (h *MockHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { +func (h *MockHook) PreApply(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { h.Lock() defer h.Unlock() h.PreApplyCalled = true h.PreApplyAddr = addr - h.PreApplyGen = gen + h.PreApplyGen = dk h.PreApplyAction = action h.PreApplyPriorState = priorState h.PreApplyPlannedState = plannedNewState return h.PreApplyReturn, h.PreApplyError } -func (h *MockHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (HookAction, error) { +func (h *MockHook) PostApply(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, newState cty.Value, err error) (HookAction, error) { h.Lock() defer h.Unlock() h.PostApplyCalled = true h.PostApplyAddr = addr - h.PostApplyGen = gen + h.PostApplyGen = dk h.PostApplyNewState = newState h.PostApplyError = err if h.PostApplyFn != nil { - return h.PostApplyFn(addr, gen, newState, err) + return h.PostApplyFn(addr, dk, newState, err) } return h.PostApplyReturn, h.PostApplyReturnError } -func (h *MockHook) PreDiff(addr addrs.AbsResourceInstance, gen states.Generation, priorState, proposedNewState cty.Value) (HookAction, error) { +func (h *MockHook) PreDiff(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, priorState, proposedNewState cty.Value) (HookAction, error) { h.Lock() defer h.Unlock() h.PreDiffCalled = true h.PreDiffAddr = addr - h.PreDiffGen = gen + h.PreDiffGen = dk h.PreDiffPriorState = priorState h.PreDiffProposedState = proposedNewState return h.PreDiffReturn, h.PreDiffError } -func (h *MockHook) PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { +func (h *MockHook) PostDiff(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { h.Lock() defer h.Unlock() h.PostDiffCalled = true h.PostDiffAddr = addr - h.PostDiffGen = gen + h.PostDiffGen = dk h.PostDiffAction = action h.PostDiffPriorState = priorState h.PostDiffPlannedState = plannedNewState @@ -247,18 +247,18 @@ func (h *MockHook) ProvisionOutput(addr addrs.AbsResourceInstance, typeName stri h.ProvisionOutputMessage = line } -func (h *MockHook) PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (HookAction, error) { +func (h *MockHook) PreRefresh(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, priorState cty.Value) (HookAction, error) { h.Lock() defer h.Unlock() h.PreRefreshCalled = true h.PreRefreshAddr = addr - h.PreRefreshGen = gen + h.PreRefreshGen = dk h.PreRefreshPriorState = priorState return h.PreRefreshReturn, h.PreRefreshError } -func (h *MockHook) PostRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value, newState cty.Value) (HookAction, error) { +func (h *MockHook) PostRefresh(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, priorState cty.Value, newState cty.Value) (HookAction, error) { h.Lock() defer h.Unlock() diff --git a/internal/terraform/hook_stop.go b/internal/terraform/hook_stop.go index 7e26c87f36..df74629abd 100644 --- a/internal/terraform/hook_stop.go +++ b/internal/terraform/hook_stop.go @@ -23,19 +23,19 @@ type stopHook struct { var _ Hook = (*stopHook)(nil) -func (h *stopHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { +func (h *stopHook) PreApply(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { return h.hook() } -func (h *stopHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (HookAction, error) { +func (h *stopHook) PostApply(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, newState cty.Value, err error) (HookAction, error) { return h.hook() } -func (h *stopHook) PreDiff(addr addrs.AbsResourceInstance, gen states.Generation, priorState, proposedNewState cty.Value) (HookAction, error) { +func (h *stopHook) PreDiff(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, priorState, proposedNewState cty.Value) (HookAction, error) { return h.hook() } -func (h *stopHook) PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { +func (h *stopHook) PostDiff(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { return h.hook() } @@ -58,11 +58,11 @@ func (h *stopHook) PostProvisionInstanceStep(addr addrs.AbsResourceInstance, typ func (h *stopHook) ProvisionOutput(addr addrs.AbsResourceInstance, typeName string, line string) { } -func (h *stopHook) PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (HookAction, error) { +func (h *stopHook) PreRefresh(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, priorState cty.Value) (HookAction, error) { return h.hook() } -func (h *stopHook) PostRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value, newState cty.Value) (HookAction, error) { +func (h *stopHook) PostRefresh(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, priorState cty.Value, newState cty.Value) (HookAction, error) { return h.hook() } diff --git a/internal/terraform/hook_test.go b/internal/terraform/hook_test.go index b5d77b9e80..c96c3d57ba 100644 --- a/internal/terraform/hook_test.go +++ b/internal/terraform/hook_test.go @@ -37,28 +37,28 @@ type testHookCall struct { InstanceID string } -func (h *testHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { +func (h *testHook) PreApply(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { h.mu.Lock() defer h.mu.Unlock() h.Calls = append(h.Calls, &testHookCall{"PreApply", addr.String()}) return HookActionContinue, nil } -func (h *testHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, err error) (HookAction, error) { +func (h *testHook) PostApply(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, newState cty.Value, err error) (HookAction, error) { h.mu.Lock() defer h.mu.Unlock() h.Calls = append(h.Calls, &testHookCall{"PostApply", addr.String()}) return HookActionContinue, nil } -func (h *testHook) PreDiff(addr addrs.AbsResourceInstance, gen states.Generation, priorState, proposedNewState cty.Value) (HookAction, error) { +func (h *testHook) PreDiff(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, priorState, proposedNewState cty.Value) (HookAction, error) { h.mu.Lock() defer h.mu.Unlock() h.Calls = append(h.Calls, &testHookCall{"PreDiff", addr.String()}) return HookActionContinue, nil } -func (h *testHook) PostDiff(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { +func (h *testHook) PostDiff(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { h.mu.Lock() defer h.mu.Unlock() h.Calls = append(h.Calls, &testHookCall{"PostDiff", addr.String()}) @@ -99,14 +99,14 @@ func (h *testHook) ProvisionOutput(addr addrs.AbsResourceInstance, typeName stri h.Calls = append(h.Calls, &testHookCall{"ProvisionOutput", addr.String()}) } -func (h *testHook) PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (HookAction, error) { +func (h *testHook) PreRefresh(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, priorState cty.Value) (HookAction, error) { h.mu.Lock() defer h.mu.Unlock() h.Calls = append(h.Calls, &testHookCall{"PreRefresh", addr.String()}) return HookActionContinue, nil } -func (h *testHook) PostRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value, newState cty.Value) (HookAction, error) { +func (h *testHook) PostRefresh(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, priorState cty.Value, newState cty.Value) (HookAction, error) { h.mu.Lock() defer h.mu.Unlock() h.Calls = append(h.Calls, &testHookCall{"PostRefresh", addr.String()}) diff --git a/internal/terraform/node_resource_abstract.go b/internal/terraform/node_resource_abstract.go index b8ffec310d..cbf4f1d16e 100644 --- a/internal/terraform/node_resource_abstract.go +++ b/internal/terraform/node_resource_abstract.go @@ -445,7 +445,7 @@ func (n *NodeAbstractResource) readResourceInstanceState(ctx EvalContext, addr a log.Printf("[TRACE] readResourceInstanceState: reading state for %s", addr) - src := ctx.State().ResourceInstanceObject(addr, states.CurrentGen) + src := ctx.State().ResourceInstanceObject(addr, addrs.NotDeposed) if src == nil { // Presumably we only have deposed objects, then. log.Printf("[TRACE] readResourceInstanceState: no state present for %s", addr) diff --git a/internal/terraform/node_resource_abstract_instance.go b/internal/terraform/node_resource_abstract_instance.go index 50663920bd..fe1e1be9d4 100644 --- a/internal/terraform/node_resource_abstract_instance.go +++ b/internal/terraform/node_resource_abstract_instance.go @@ -161,8 +161,7 @@ func (n *NodeAbstractResourceInstance) readDiff(ctx EvalContext, providerSchema return nil, fmt.Errorf("provider does not support resource type %q", addr.Resource.Resource.Type) } - gen := states.CurrentGen - csrc := changes.GetResourceInstanceChange(addr, gen) + csrc := changes.GetResourceInstanceChange(addr, addrs.NotDeposed) if csrc == nil { log.Printf("[TRACE] readDiff: No planned change recorded for %s", n.Addr) return nil, nil @@ -216,7 +215,7 @@ func (n *NodeAbstractResourceInstance) preApplyHook(ctx EvalContext, change *pla plannedNewState := change.After diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PreApply(n.Addr, change.DeposedKey.Generation(), change.Action, priorState, plannedNewState) + return h.PreApply(n.Addr, change.DeposedKey, change.Action, priorState, plannedNewState) })) if diags.HasErrors() { return diags @@ -239,7 +238,7 @@ func (n *NodeAbstractResourceInstance) postApplyHook(ctx EvalContext, state *sta newState = cty.NullVal(cty.DynamicPseudoType) } diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PostApply(n.Addr, nil, newState, err) + return h.PostApply(n.Addr, addrs.NotDeposed, newState, err) })) } @@ -484,11 +483,7 @@ func (n *NodeAbstractResourceInstance) writeChange(ctx EvalContext, change *plan if change == nil { // Caller sets nil to indicate that we need to remove a change from // the set of changes. - gen := states.CurrentGen - if deposedKey != states.NotDeposed { - gen = deposedKey - } - changes.RemoveResourceInstanceChange(n.Addr, gen) + changes.RemoveResourceInstanceChange(n.Addr, deposedKey) return nil } @@ -566,14 +561,9 @@ func (n *NodeAbstractResourceInstance) refresh(ctx EvalContext, deposedKey state return state, diags } - hookGen := states.CurrentGen - if deposedKey != states.NotDeposed { - hookGen = deposedKey - } - // Call pre-refresh hook diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PreRefresh(absAddr, hookGen, state.Value) + return h.PreRefresh(absAddr, deposedKey, state.Value) })) if diags.HasErrors() { return state, diags @@ -660,7 +650,7 @@ func (n *NodeAbstractResourceInstance) refresh(ctx EvalContext, deposedKey state // Call post-refresh hook diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PostRefresh(absAddr, hookGen, priorVal, ret.Value) + return h.PostRefresh(absAddr, deposedKey, priorVal, ret.Value) })) if diags.HasErrors() { return ret, diags @@ -824,7 +814,7 @@ func (n *NodeAbstractResourceInstance) plan( // Call pre-diff hook diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PreDiff(n.Addr, states.CurrentGen, priorVal, proposedNewVal) + return h.PreDiff(n.Addr, addrs.NotDeposed, priorVal, proposedNewVal) })) if diags.HasErrors() { return nil, nil, keyData, diags @@ -1178,7 +1168,7 @@ func (n *NodeAbstractResourceInstance) plan( // Call post-refresh hook diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PostDiff(n.Addr, states.CurrentGen, action, priorVal, plannedNewVal) + return h.PostDiff(n.Addr, addrs.NotDeposed, action, priorVal, plannedNewVal) })) if diags.HasErrors() { return nil, nil, keyData, diags @@ -1505,7 +1495,7 @@ func (n *NodeAbstractResourceInstance) readDataSource(ctx EvalContext, configVal log.Printf("[TRACE] readDataSource: %s configuration is complete, so reading from provider", n.Addr) diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PreApply(n.Addr, states.CurrentGen, plans.Read, cty.NullVal(configVal.Type()), configVal) + return h.PreApply(n.Addr, addrs.NotDeposed, plans.Read, cty.NullVal(configVal.Type()), configVal) })) if diags.HasErrors() { return newVal, diags @@ -1588,7 +1578,7 @@ func (n *NodeAbstractResourceInstance) readDataSource(ctx EvalContext, configVal } diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PostApply(n.Addr, states.CurrentGen, newVal, diags.Err()) + return h.PostApply(n.Addr, addrs.NotDeposed, newVal, diags.Err()) })) return newVal, diags @@ -1754,7 +1744,7 @@ func (n *NodeAbstractResourceInstance) planDataSource(ctx EvalContext, checkRule } diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PostDiff(n.Addr, states.CurrentGen, plans.Read, priorVal, proposedNewVal) + return h.PostDiff(n.Addr, addrs.NotDeposed, plans.Read, priorVal, proposedNewVal) })) return plannedChange, plannedNewState, keyData, diags @@ -1944,7 +1934,7 @@ func (n *NodeAbstractResourceInstance) applyDataSource(ctx EvalContext, planned diags = diags.Append(checkDiags) if diags.HasErrors() { diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) { - return h.PostApply(n.Addr, states.CurrentGen, planned.Before, diags.Err()) + return h.PostApply(n.Addr, addrs.NotDeposed, planned.Before, diags.Err()) })) return nil, keyData, diags // failed preconditions prevent further evaluation } diff --git a/internal/terraform/node_resource_apply_instance.go b/internal/terraform/node_resource_apply_instance.go index 68524953ea..98c6376254 100644 --- a/internal/terraform/node_resource_apply_instance.go +++ b/internal/terraform/node_resource_apply_instance.go @@ -122,7 +122,7 @@ func (n *NodeApplyableResourceInstance) Execute(ctx EvalContext, op walkOperatio // to do and the change was left in the plan for informational // purposes only. changes := ctx.Changes() - csrc := changes.GetResourceInstanceChange(n.ResourceInstanceAddr(), states.CurrentGen) + csrc := changes.GetResourceInstanceChange(n.ResourceInstanceAddr(), addrs.NotDeposed) if csrc == nil || csrc.Action == plans.NoOp { log.Printf("[DEBUG] NodeApplyableResourceInstance: No config or planned change recorded for %s", n.Addr) return nil diff --git a/internal/terraform/terraform_test.go b/internal/terraform/terraform_test.go index c4b5787984..224abf5098 100644 --- a/internal/terraform/terraform_test.go +++ b/internal/terraform/terraform_test.go @@ -263,7 +263,7 @@ type HookRecordApplyOrder struct { l sync.Mutex } -func (h *HookRecordApplyOrder) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { +func (h *HookRecordApplyOrder) PreApply(addr addrs.AbsResourceInstance, dk addrs.DeposedKey, action plans.Action, priorState, plannedNewState cty.Value) (HookAction, error) { if plannedNewState.RawEquals(priorState) { return HookActionContinue, nil }