exec: ResourceInstanceObject represents an object and its address

During execution graph processing we need to carry addressing information
along with objects so that we can model changes of address as data flow
rather than as modifications to global mutable state.

In previous commits we arranged for other relevant types to track this
information, but the representation of a resource instance object was not
included because that was a messier change to wire in. This commit deals
with that mess: it introduces exec.ResourceInstanceObject to associate a
resource instance object with addressing information, and then adopts that
as the canonical representation of a "resource instance object result"
throughout all of the execution graph operations.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
This commit is contained in:
Martin Atkins 2026-01-20 11:56:08 -08:00
parent 2af3eff7b5
commit c1690a0ccf
18 changed files with 236 additions and 136 deletions

View file

@ -11,6 +11,7 @@ import (
"log"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/engine/internal/exec"
"github.com/opentofu/opentofu/internal/lang/eval"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/tfdiags"
@ -29,15 +30,15 @@ func (ops *execOperations) ResourceInstanceDesired(
func (ops *execOperations) ResourceInstancePrior(
ctx context.Context,
instAddr addrs.AbsResourceInstance,
) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics) {
) (*exec.ResourceInstanceObject, tfdiags.Diagnostics) {
log.Printf("[TRACE] applying: ResourceInstancePrior %s", instAddr)
return ops.resourceInstancePriorStateObject(ctx, instAddr, states.NotDeposed)
return ops.resourceInstanceStateObject(ctx, ops.priorState, instAddr, states.NotDeposed)
}
// ResourceInstancePostconditions implements [exec.Operations].
func (ops *execOperations) ResourceInstancePostconditions(
ctx context.Context,
result *states.ResourceInstanceObjectFull,
result *exec.ResourceInstanceObject,
) tfdiags.Diagnostics {
log.Printf("[TRACE] applying: ResourceInstancePostconditions (currently just a noop!)")
// TODO: Implement this by delegating to a special "run resource instance
@ -46,11 +47,12 @@ func (ops *execOperations) ResourceInstancePostconditions(
}
// ResourceInstancePrior implements [exec.Operations].
func (ops *execOperations) resourceInstancePriorStateObject(
func (ops *execOperations) resourceInstanceStateObject(
ctx context.Context,
fromState *states.SyncState,
instAddr addrs.AbsResourceInstance,
deposedKey states.DeposedKey,
) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics) {
) (*exec.ResourceInstanceObject, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
src := ops.priorState.ResourceInstanceObjectFull(instAddr, deposedKey)
if src == nil {
@ -69,7 +71,7 @@ func (ops *execOperations) resourceInstancePriorStateObject(
if moreDiags.HasErrors() {
return nil, diags
}
ret, err := states.DecodeResourceInstanceObjectFull(src, schema.Block.ImpliedType())
state, err := states.DecodeResourceInstanceObjectFull(src, schema.Block.ImpliedType())
if err != nil {
nounPhrase := "a current object"
if deposedKey != states.NotDeposed {
@ -85,5 +87,12 @@ func (ops *execOperations) resourceInstancePriorStateObject(
))
return nil, diags
}
return ret, diags
if state == nil {
return nil, diags
}
return &exec.ResourceInstanceObject{
InstanceAddr: instAddr,
DeposedKey: deposedKey,
State: state,
}, diags
}

View file

@ -13,7 +13,6 @@ import (
"github.com/opentofu/opentofu/internal/engine/internal/exec"
"github.com/opentofu/opentofu/internal/lang/eval"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/tfdiags"
)
@ -23,7 +22,7 @@ func (ops *execOperations) DataRead(
desired *eval.DesiredResourceInstance,
plannedVal cty.Value,
providerClient *exec.ProviderClient,
) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics) {
) (*exec.ResourceInstanceObject, tfdiags.Diagnostics) {
log.Printf("[TRACE] applying: DataRead %s", desired.Addr)
panic("unimplemented")
}

View file

@ -11,14 +11,13 @@ import (
"github.com/opentofu/opentofu/internal/engine/internal/exec"
"github.com/opentofu/opentofu/internal/lang/eval"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/tfdiags"
)
// EphemeralClose implements [exec.Operations].
func (ops *execOperations) EphemeralClose(
ctx context.Context,
object *states.ResourceInstanceObjectFull,
object *exec.ResourceInstanceObject,
providerClient *exec.ProviderClient,
) tfdiags.Diagnostics {
// FIXME: Track instance address on resource instance objects
@ -31,7 +30,7 @@ func (ops *execOperations) EphemeralOpen(
ctx context.Context,
desired *eval.DesiredResourceInstance,
providerClient *exec.ProviderClient,
) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics) {
) (*exec.ResourceInstanceObject, tfdiags.Diagnostics) {
log.Printf("[TRACE] applying: EphemeralOpen %s", desired.Addr)
panic("unimplemented")
}

View file

@ -22,7 +22,7 @@ import (
func (ops *execOperations) ManagedFinalPlan(
ctx context.Context,
desired *eval.DesiredResourceInstance,
prior *states.ResourceInstanceObjectFull,
prior *exec.ResourceInstanceObject,
plannedVal cty.Value,
providerClient *exec.ProviderClient,
) (*exec.ManagedResourceObjectFinalPlan, tfdiags.Diagnostics) {
@ -35,15 +35,15 @@ func (ops *execOperations) ManagedFinalPlan(
// change, so we'll arbitrarily choose to prefer the desired address
// whenever both are set.
instAddr = desired.Addr
// (deposed objects are never "desired")
} else if prior != nil {
// FIXME: ResourceInstanceObjectFull must carry identity with it so
// we can know what we're working with when we're planning destroy.
//instAddr = prior.Addr
//deposedKey = prior.DeposedKey
instAddr = prior.InstanceAddr
deposedKey = prior.DeposedKey
} else {
// Both should not be nil but if they are then we'll treat it the same
// way as if we dynamically discover that no change is actually
// required, by returning a nil final plan to represent "noop".
log.Printf("[TRACE] applying: ManagedFinalPlan without either desired or prior state, so no change is needed")
return nil, nil
}
if deposedKey == states.NotDeposed {
@ -58,9 +58,9 @@ func (ops *execOperations) ManagedFinalPlan(
func (ops *execOperations) ManagedApply(
ctx context.Context,
plan *exec.ManagedResourceObjectFinalPlan,
fallback *states.ResourceInstanceObjectFull,
fallback *exec.ResourceInstanceObject,
providerClient *exec.ProviderClient,
) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics) {
) (*exec.ResourceInstanceObject, tfdiags.Diagnostics) {
if plan == nil {
// TODO: if "fallback" is set then we should set it as current here to
// honor the overall contract. In practice we currently never construct
@ -93,9 +93,17 @@ func (ops *execOperations) ManagedApply(
func (ops *execOperations) ManagedDepose(
ctx context.Context,
instAddr addrs.AbsResourceInstance,
) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics) {
) (*exec.ResourceInstanceObject, tfdiags.Diagnostics) {
log.Printf("[TRACE] applying: ManagedDepose %s", instAddr)
panic("unimplemented")
var diags tfdiags.Diagnostics
deposedKey := ops.workingState.DeposeResourceInstanceObject(instAddr)
if deposedKey == states.NotDeposed {
// This means that there was no "current" object to depose, and
// so we'll return nil to represent that there's nothing here.
return nil, diags
}
return ops.resourceInstanceStateObject(ctx, ops.workingState, instAddr, deposedKey)
}
// ManagedAlreadyDeposed implements [exec.Operations].
@ -103,10 +111,10 @@ func (ops *execOperations) ManagedAlreadyDeposed(
ctx context.Context,
instAddr addrs.AbsResourceInstance,
deposedKey states.DeposedKey,
) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics) {
) (*exec.ResourceInstanceObject, tfdiags.Diagnostics) {
log.Printf("[TRACE] applying: ManagedAlreadyDeposed %s deposed object %s", instAddr, deposedKey)
// This is essentially the same as ResourceInstancePrior, but for deposed
// objects rather than "current" objects. Therefore we'll share most of the
// implementation between these two.
return ops.resourceInstancePriorStateObject(ctx, instAddr, deposedKey)
return ops.resourceInstanceStateObject(ctx, ops.priorState, instAddr, deposedKey)
}

View file

@ -113,7 +113,7 @@ type Operations interface {
ResourceInstancePrior(
ctx context.Context,
instAddr addrs.AbsResourceInstance,
) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics)
) (*ResourceInstanceObject, tfdiags.Diagnostics)
// ResourceInstancePostconditions tests whether the given object passes
// any postconditions that were declared for it.
@ -125,7 +125,7 @@ type Operations interface {
// handled consistently for all resource modes.
ResourceInstancePostconditions(
ctx context.Context,
result *states.ResourceInstanceObjectFull,
result *ResourceInstanceObject,
) tfdiags.Diagnostics
//////////////////////////////////////////////////////////////////////////////
@ -148,7 +148,7 @@ type Operations interface {
ManagedFinalPlan(
ctx context.Context,
desired *eval.DesiredResourceInstance,
prior *states.ResourceInstanceObjectFull,
prior *ResourceInstanceObject,
plannedVal cty.Value,
providerClient *ProviderClient,
) (*ManagedResourceObjectFinalPlan, tfdiags.Diagnostics)
@ -187,9 +187,9 @@ type Operations interface {
ManagedApply(
ctx context.Context,
plan *ManagedResourceObjectFinalPlan,
fallback *states.ResourceInstanceObjectFull,
fallback *ResourceInstanceObject,
providerClient *ProviderClient,
) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics)
) (*ResourceInstanceObject, tfdiags.Diagnostics)
// ManagedDepose transforms the "current" object associated with the given
// resource instance address into a "deposed" object for the same resource
@ -206,7 +206,7 @@ type Operations interface {
ManagedDepose(
ctx context.Context,
instAddr addrs.AbsResourceInstance,
) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics)
) (*ResourceInstanceObject, tfdiags.Diagnostics)
// ManagedAlreadyDeposed returns a deposed object from the prior state,
// nor nil if there is no such object.
@ -225,7 +225,7 @@ type Operations interface {
ctx context.Context,
instAddr addrs.AbsResourceInstance,
deposedKey states.DeposedKey,
) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics)
) (*ResourceInstanceObject, tfdiags.Diagnostics)
//////////////////////////////////////////////////////////////////////////////
/// Resource-related operations that are relevant only for data resources.
@ -253,7 +253,7 @@ type Operations interface {
desired *eval.DesiredResourceInstance,
plannedVal cty.Value,
providerClient *ProviderClient,
) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics)
) (*ResourceInstanceObject, tfdiags.Diagnostics)
//////////////////////////////////////////////////////////////////////////////
/// Resource-related operations that are relevant only for ephemeral resources.
@ -280,7 +280,7 @@ type Operations interface {
ctx context.Context,
desired *eval.DesiredResourceInstance,
providerClient *ProviderClient,
) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics)
) (*ResourceInstanceObject, tfdiags.Diagnostics)
// EphemeralClose uses the given provider client to "close" the given
// ephemeral object.
@ -292,7 +292,7 @@ type Operations interface {
// after this method returns.
EphemeralClose(
ctx context.Context,
object *states.ResourceInstanceObjectFull,
object *ResourceInstanceObject,
providerClient *ProviderClient,
) tfdiags.Diagnostics
}

View file

@ -6,9 +6,10 @@
package exec
import (
"github.com/zclconf/go-cty/cty"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/states"
"github.com/zclconf/go-cty/cty"
)
// ManagedResourceObjectFinalPlan represents a final plan -- ready to actually
@ -64,3 +65,71 @@ type ManagedResourceObjectFinalPlan struct {
// TODO: Anything else we'd need to populate an "ApplyResourceChanges"
// request to the associated provider.
}
// ResourceInstanceObject associates a [states.ResourceInstanceObjectFull] with
// a resource instance address and optional deposed key.
//
// Objects of this type should be treated as immutable. Use the methods of this
// type to derive new objects when modelling changes.
//
// This is intended to model the idea that an object can move between different
// tracking addresses without being modified: an instance of this type
// represents the object existing at a particular address, with the intention
// that a caller would create a new object of this type whenever an object
// moves between addresses but should not need to change the underlying object
// itself.
//
// If an operation _does_ cause an object to move to a new tracking address then
// it should be designed to take an object of this type as an argument
// representing the starting location and then to return a newly-constructed
// separate object of this type representing the new location, so that the
// change of address is modelled in the data flow between operations rather than
// as global mutable state.
type ResourceInstanceObject struct {
InstanceAddr addrs.AbsResourceInstance
DeposedKey states.DeposedKey
// State is the object currently associated with the given address.
State *states.ResourceInstanceObjectFull
}
// IntoCurrent returns a new [ResourceInstanceObject] that has the same
// State as the receiver but has DeposedKey set to [states.NotDeposed].
func (o *ResourceInstanceObject) IntoCurrent() *ResourceInstanceObject {
return &ResourceInstanceObject{
InstanceAddr: o.InstanceAddr,
DeposedKey: states.NotDeposed,
State: o.State,
}
}
// IntoCurrent returns a new [ResourceInstanceObject] that has the same
// State as the receiver but has DeposedKey set the given value.
//
// This function does not (and cannot) verify that the chosen deposed key is
// unique for the resource instance. It's the caller's responsibility to
// allocate a unique deposed key to use.
func (o *ResourceInstanceObject) IntoDeposed(key states.DeposedKey) *ResourceInstanceObject {
return &ResourceInstanceObject{
InstanceAddr: o.InstanceAddr,
DeposedKey: key,
State: o.State,
}
}
// IntoCurrent returns a new [ResourceInstanceObject] that has the same
// address information as the receiver but has State set to the given object.
//
// If the given state object is nil then the result is also nil, to represent
// the absense of an object. [ResourceInstanceObject] instances should only
// represent objects that actually exist.
func (o *ResourceInstanceObject) WithNewState(newState *states.ResourceInstanceObjectFull) *ResourceInstanceObject {
if newState == nil {
return nil
}
return &ResourceInstanceObject{
InstanceAddr: o.InstanceAddr,
DeposedKey: o.DeposedKey,
State: newState,
}
}

View file

@ -14,7 +14,6 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/engine/internal/exec"
"github.com/opentofu/opentofu/internal/lang/eval"
"github.com/opentofu/opentofu/internal/states"
)
// Builder is a helper for multiple codepaths to collaborate to build an
@ -46,7 +45,7 @@ type Builder struct {
func NewBuilder() *Builder {
return &Builder{
graph: &Graph{
resourceInstanceResults: addrs.MakeMap[addrs.AbsResourceInstance, ResultRef[*states.ResourceInstanceObjectFull]](),
resourceInstanceResults: addrs.MakeMap[addrs.AbsResourceInstance, ResourceInstanceResultRef](),
},
resourceInstAddrRefs: addrs.MakeMap[addrs.AbsResourceInstance, ResultRef[addrs.AbsResourceInstance]](),
providerInstAddrRefs: addrs.MakeMap[addrs.AbsProviderInstanceCorrect, ResultRef[addrs.AbsProviderInstanceCorrect]](),
@ -239,7 +238,7 @@ func (b *Builder) ResourceInstancePrior(
b.mu.Lock()
defer b.mu.Unlock()
return operationRef[*states.ResourceInstanceObjectFull](b, operationDesc{
return operationRef[*exec.ResourceInstanceObject](b, operationDesc{
opCode: opResourceInstancePrior,
operands: []AnyResultRef{addr},
})
@ -263,7 +262,7 @@ func (b *Builder) ResourceInstancePrior(
// both be set when handling an in-place update.
func (b *Builder) ManagedFinalPlan(
desiredInst ResultRef[*eval.DesiredResourceInstance],
priorState ResultRef[*states.ResourceInstanceObjectFull],
priorState ResourceInstanceResultRef,
plannedVal ResultRef[cty.Value],
providerClient ResultRef[*exec.ProviderClient],
) ResultRef[*exec.ManagedResourceObjectFinalPlan] {
@ -281,15 +280,20 @@ func (b *Builder) ManagedFinalPlan(
//
// The finalPlan argument should typically be something returned by a previous
// call to [Builder.ManagedFinalPlan] with the same provider client.
//
// fallbackObj is usually a [NilResultRef], but should be set for the "create"
// leg of a "create then destroy" replace operation to be the result of a
// call to [Builder.ManagedDepose] so that the deposed object can be restored
// to current if the create call completely fails to create a new object.
func (b *Builder) ManagedApply(
finalPlan ResultRef[*exec.ManagedResourceObjectFinalPlan],
fallbackObj ResultRef[*states.ResourceInstanceObjectFull],
fallbackObj ResourceInstanceResultRef,
providerClient ResultRef[*exec.ProviderClient],
) ResourceInstanceResultRef {
b.mu.Lock()
defer b.mu.Unlock()
return operationRef[*states.ResourceInstanceObjectFull](b, operationDesc{
return operationRef[*exec.ResourceInstanceObject](b, operationDesc{
opCode: opManagedApply,
operands: []AnyResultRef{finalPlan, fallbackObj, providerClient},
})
@ -301,7 +305,7 @@ func (b *Builder) ManagedDepose(
b.mu.Lock()
defer b.mu.Unlock()
return operationRef[*states.ResourceInstanceObjectFull](b, operationDesc{
return operationRef[*exec.ResourceInstanceObject](b, operationDesc{
opCode: opManagedDepose,
operands: []AnyResultRef{instAddr},
})
@ -313,7 +317,7 @@ func (b *Builder) ManagedAlreadyDeposed(
b.mu.Lock()
defer b.mu.Unlock()
return operationRef[*states.ResourceInstanceObjectFull](b, operationDesc{
return operationRef[*exec.ResourceInstanceObject](b, operationDesc{
opCode: opManagedAlreadyDeposed,
operands: []AnyResultRef{instAddr},
})
@ -327,7 +331,7 @@ func (b *Builder) DataRead(
b.mu.Lock()
defer b.mu.Unlock()
return operationRef[*states.ResourceInstanceObjectFull](b, operationDesc{
return operationRef[*exec.ResourceInstanceObject](b, operationDesc{
opCode: opDataRead,
operands: []AnyResultRef{desiredInst, plannedVal, providerClient},
})
@ -340,7 +344,7 @@ func (b *Builder) EphemeralOpen(
b.mu.Lock()
defer b.mu.Unlock()
return operationRef[*states.ResourceInstanceObjectFull](b, operationDesc{
return operationRef[*exec.ResourceInstanceObject](b, operationDesc{
opCode: opEphemeralOpen,
operands: []AnyResultRef{desiredInst, providerClient},
})

View file

@ -11,7 +11,7 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/engine/internal/exec"
"github.com/zclconf/go-cty/cty"
)
@ -47,7 +47,7 @@ func TestBuilder_basics(t *testing.T) {
providerClient,
)
newState := builder.ManagedApply(
finalPlan, NilResultRef[*states.ResourceInstanceObjectFull](), providerClient,
finalPlan, NilResultRef[*exec.ResourceInstanceObject](), providerClient,
)
addProviderUser(newState)
builder.SetResourceInstanceFinalStateResult(resourceInstAddr, newState)

View file

@ -17,7 +17,6 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/engine/internal/exec"
"github.com/opentofu/opentofu/internal/lang/grapheval"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/tfdiags"
)
@ -177,11 +176,11 @@ func (c *compiler) Compile() (*CompiledGraph, tfdiags.Diagnostics) {
if !ok {
return cty.DynamicVal
}
finalStateObj := rawResult.(*states.ResourceInstanceObjectFull)
finalStateObj := rawResult.(*exec.ResourceInstanceObject)
if finalStateObj == nil {
return cty.NullVal(cty.DynamicPseudoType)
}
return finalStateObj.Value
return finalStateObj.State.Value
})
}

View file

@ -175,7 +175,7 @@ func (c *compiler) compileOpResourceInstancePrior(operands *compilerOperands) no
func (c *compiler) compileOpManagedFinalPlan(operands *compilerOperands) nodeExecuteRaw {
getDesired := nextOperand[*eval.DesiredResourceInstance](operands)
getPrior := nextOperand[*states.ResourceInstanceObjectFull](operands)
getPrior := nextOperand[*exec.ResourceInstanceObject](operands)
getInitialPlanned := nextOperand[cty.Value](operands)
getProviderClient := nextOperand[*exec.ProviderClient](operands)
diags := operands.Finish()
@ -224,7 +224,7 @@ func (c *compiler) compileOpManagedFinalPlan(operands *compilerOperands) nodeExe
func (c *compiler) compileOpManagedApply(operands *compilerOperands) nodeExecuteRaw {
getFinalPlan := nextOperand[*exec.ManagedResourceObjectFinalPlan](operands)
getFallback := nextOperand[*states.ResourceInstanceObjectFull](operands)
getFallback := nextOperand[*exec.ResourceInstanceObject](operands)
getProviderClient := nextOperand[*exec.ProviderClient](operands)
diags := operands.Finish()
c.diags = c.diags.Append(diags)
@ -405,7 +405,7 @@ func (c *compiler) compileOpEphemeralOpen(operands *compilerOperands) nodeExecut
}
func (c *compiler) compileOpEphemeralClose(operands *compilerOperands) nodeExecuteRaw {
getObject := nextOperand[*states.ResourceInstanceObjectFull](operands)
getObject := nextOperand[*exec.ResourceInstanceObject](operands)
getProviderClient := nextOperand[*exec.ProviderClient](operands)
diags := operands.Finish()
c.diags = c.diags.Append(diags)

View file

@ -64,7 +64,7 @@ func TestCompiler_resourceInstanceBasics(t *testing.T) {
providerClient,
)
newState := builder.ManagedApply(
finalPlan, NilResultRef[*states.ResourceInstanceObjectFull](), providerClient,
finalPlan, NilResultRef[*exec.ResourceInstanceObject](), providerClient,
)
addProviderUser(newState)
builder.SetResourceInstanceFinalStateResult(resourceInstAddr, newState)
@ -92,37 +92,43 @@ func TestCompiler_resourceInstanceBasics(t *testing.T) {
ResourceType: addr.Resource.Resource.Type,
}, nil
},
ResourceInstancePriorFunc: func(ctx context.Context, addr addrs.AbsResourceInstance) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics) {
return &states.ResourceInstanceObjectFull{
Status: states.ObjectReady,
Value: cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prior"),
}),
ProviderInstanceAddr: addrs.AbsProviderInstanceCorrect{
Config: addrs.AbsProviderConfigCorrect{
Config: addrs.ProviderConfigCorrect{
Provider: addrs.NewBuiltInProvider("test"),
ResourceInstancePriorFunc: func(ctx context.Context, addr addrs.AbsResourceInstance) (*exec.ResourceInstanceObject, tfdiags.Diagnostics) {
return &exec.ResourceInstanceObject{
InstanceAddr: addr,
State: &states.ResourceInstanceObjectFull{
Status: states.ObjectReady,
Value: cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prior"),
}),
ProviderInstanceAddr: addrs.AbsProviderInstanceCorrect{
Config: addrs.AbsProviderConfigCorrect{
Config: addrs.ProviderConfigCorrect{
Provider: addrs.NewBuiltInProvider("test"),
},
},
},
ResourceType: addr.Resource.Resource.Type,
},
ResourceType: addr.Resource.Resource.Type,
}, nil
},
ManagedFinalPlanFunc: func(ctx context.Context, desired *eval.DesiredResourceInstance, prior *states.ResourceInstanceObjectFull, plannedVal cty.Value, providerClient *exec.ProviderClient) (*exec.ManagedResourceObjectFinalPlan, tfdiags.Diagnostics) {
ManagedFinalPlanFunc: func(ctx context.Context, desired *eval.DesiredResourceInstance, prior *exec.ResourceInstanceObject, plannedVal cty.Value, providerClient *exec.ProviderClient) (*exec.ManagedResourceObjectFinalPlan, tfdiags.Diagnostics) {
return &exec.ManagedResourceObjectFinalPlan{
InstanceAddr: desired.Addr,
ResourceType: desired.ResourceType,
ConfigVal: desired.ConfigVal,
PriorStateVal: prior.Value,
PriorStateVal: prior.State.Value,
PlannedVal: plannedVal,
}, nil
},
ManagedApplyFunc: func(ctx context.Context, plan *exec.ManagedResourceObjectFinalPlan, fallback *states.ResourceInstanceObjectFull, providerClient *exec.ProviderClient) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics) {
return &states.ResourceInstanceObjectFull{
Status: states.ObjectReady,
Value: plan.PlannedVal,
ResourceType: plan.ResourceType,
ProviderInstanceAddr: providerClient.InstanceAddr,
ManagedApplyFunc: func(ctx context.Context, plan *exec.ManagedResourceObjectFinalPlan, fallback *exec.ResourceInstanceObject, providerClient *exec.ProviderClient) (*exec.ResourceInstanceObject, tfdiags.Diagnostics) {
return &exec.ResourceInstanceObject{
InstanceAddr: plan.InstanceAddr,
State: &states.ResourceInstanceObjectFull{
Status: states.ObjectReady,
Value: plan.PlannedVal,
ResourceType: plan.ResourceType,
ProviderInstanceAddr: providerClient.InstanceAddr,
},
}, nil
},
ProviderInstanceConfigFunc: func(ctx context.Context, addr addrs.AbsProviderInstanceCorrect) (*exec.ProviderInstanceConfig, tfdiags.Diagnostics) {
@ -214,14 +220,17 @@ func TestCompiler_resourceInstanceBasics(t *testing.T) {
"name": cty.StringVal("prior"),
}),
},
(*states.ResourceInstanceObjectFull)(nil),
(*exec.ResourceInstanceObject)(nil),
providerInstAddr,
},
Result: &states.ResourceInstanceObjectFull{
Status: states.ObjectReady,
Value: wantValue,
ProviderInstanceAddr: providerInstAddr,
ResourceType: resourceInstAddr.Resource.Resource.Type,
Result: &exec.ResourceInstanceObject{
InstanceAddr: resourceInstAddr,
State: &states.ResourceInstanceObjectFull{
Status: states.ObjectReady,
Value: wantValue,
ProviderInstanceAddr: providerInstAddr,
ResourceType: resourceInstAddr.Resource.Resource.Type,
},
},
},
{
@ -235,19 +244,22 @@ func TestCompiler_resourceInstanceBasics(t *testing.T) {
ResourceMode: addrs.ManagedResourceMode,
ResourceType: resourceInstAddr.Resource.Resource.Type,
},
&states.ResourceInstanceObjectFull{
Status: states.ObjectReady,
Value: cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prior"),
}),
ProviderInstanceAddr: addrs.AbsProviderInstanceCorrect{
Config: addrs.AbsProviderConfigCorrect{
Config: addrs.ProviderConfigCorrect{
Provider: addrs.NewBuiltInProvider("test"),
&exec.ResourceInstanceObject{
InstanceAddr: resourceInstAddr,
State: &states.ResourceInstanceObjectFull{
Status: states.ObjectReady,
Value: cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prior"),
}),
ProviderInstanceAddr: addrs.AbsProviderInstanceCorrect{
Config: addrs.AbsProviderConfigCorrect{
Config: addrs.ProviderConfigCorrect{
Provider: addrs.NewBuiltInProvider("test"),
},
},
},
ResourceType: resourceInstAddr.Resource.Resource.Type,
},
ResourceType: resourceInstAddr.Resource.Resource.Type,
},
wantValue,
providerInstAddr,
@ -312,19 +324,22 @@ func TestCompiler_resourceInstanceBasics(t *testing.T) {
Args: []any{
resourceInstAddr,
},
Result: &states.ResourceInstanceObjectFull{
Status: states.ObjectReady,
Value: cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prior"),
}),
ProviderInstanceAddr: addrs.AbsProviderInstanceCorrect{
Config: addrs.AbsProviderConfigCorrect{
Config: addrs.ProviderConfigCorrect{
Provider: addrs.NewBuiltInProvider("test"),
Result: &exec.ResourceInstanceObject{
InstanceAddr: resourceInstAddr,
State: &states.ResourceInstanceObjectFull{
Status: states.ObjectReady,
Value: cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prior"),
}),
ProviderInstanceAddr: addrs.AbsProviderInstanceCorrect{
Config: addrs.AbsProviderConfigCorrect{
Config: addrs.ProviderConfigCorrect{
Provider: addrs.NewBuiltInProvider("test"),
},
},
},
ResourceType: resourceInstAddr.Resource.Resource.Type,
},
ResourceType: resourceInstAddr.Resource.Resource.Type,
},
},
}

View file

@ -15,7 +15,6 @@ import (
"github.com/zclconf/go-cty/cty"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/states"
)
type Graph struct {
@ -79,7 +78,7 @@ type Graph struct {
// operation for each resource instance should also directly depend on
// the results of any resource instances that were identified as
// resource-instance-graph dependencies during the planning process.
resourceInstanceResults addrs.Map[addrs.AbsResourceInstance, ResultRef[*states.ResourceInstanceObjectFull]]
resourceInstanceResults addrs.Map[addrs.AbsResourceInstance, ResourceInstanceResultRef]
}
// DebugRepr returns a relatively-concise string representation of the

View file

@ -14,7 +14,6 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/engine/internal/execgraph/execgraphproto"
"github.com/opentofu/opentofu/internal/states"
)
// Marshal produces an opaque byte slice representing the given graph,
@ -63,7 +62,7 @@ func (m *graphMarshaler) EnsureOperationPresent(idx int) uint64 {
return m.ensureRefTarget(erasedRef)
}
func (m *graphMarshaler) EnsureResourceInstanceResultsPresent(results addrs.Map[addrs.AbsResourceInstance, ResultRef[*states.ResourceInstanceObjectFull]]) {
func (m *graphMarshaler) EnsureResourceInstanceResultsPresent(results addrs.Map[addrs.AbsResourceInstance, ResourceInstanceResultRef]) {
m.resourceInstanceResults = make(map[string]uint64)
for _, mapElem := range results.Elems {
instAddr := mapElem.Key

View file

@ -17,8 +17,8 @@ import (
"google.golang.org/protobuf/proto"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/engine/internal/exec"
"github.com/opentofu/opentofu/internal/engine/internal/execgraph/execgraphproto"
"github.com/opentofu/opentofu/internal/states"
)
func TestGraphMarshalUnmarshalValid(t *testing.T) {
@ -84,7 +84,7 @@ func TestGraphMarshalUnmarshalValid(t *testing.T) {
nil,
)
finalPlan := builder.ManagedFinalPlan(desiredInst, priorState, plannedVal, providerClient)
newState := builder.ManagedApply(finalPlan, NilResultRef[*states.ResourceInstanceObjectFull](), providerClient)
newState := builder.ManagedApply(finalPlan, NilResultRef[*exec.ResourceInstanceObject](), providerClient)
registerUser(newState)
builder.SetResourceInstanceFinalStateResult(instAddr, newState)
return builder.Finish()

View file

@ -17,7 +17,6 @@ import (
"github.com/opentofu/opentofu/internal/engine/internal/exec"
"github.com/opentofu/opentofu/internal/engine/internal/execgraph/execgraphproto"
"github.com/opentofu/opentofu/internal/lang/eval"
"github.com/opentofu/opentofu/internal/states"
)
// UnmarshalGraph takes some bytes previously returned by [Graph.Marshal] and
@ -102,7 +101,7 @@ func UnmarshalGraph(src []byte) (*Graph, error) {
if diags.HasErrors() {
return nil, fmt.Errorf("invalid resource instance address %q: %w", instAddrStr, diags.Err())
}
resultRef, err := unmarshalGetPrevResultOf[*states.ResourceInstanceObjectFull](results, resultIdx)
resultRef, err := unmarshalGetPrevResultOf[*exec.ResourceInstanceObject](results, resultIdx)
if err != nil {
return nil, fmt.Errorf("invalid result element for %s: %w", instAddr, err)
}
@ -221,7 +220,7 @@ func unmarshalOpManagedFinalPlan(rawOperands []uint64, prevResults []AnyResultRe
if err != nil {
return nil, fmt.Errorf("invalid opManagedFinalPlan desiredInst: %w", err)
}
priorState, err := unmarshalGetPrevResultOf[*states.ResourceInstanceObjectFull](prevResults, rawOperands[1])
priorState, err := unmarshalGetPrevResultOf[*exec.ResourceInstanceObject](prevResults, rawOperands[1])
if err != nil {
return nil, fmt.Errorf("invalid opManagedFinalPlan priorState: %w", err)
}
@ -244,7 +243,7 @@ func unmarshalOpManagedApply(rawOperands []uint64, prevResults []AnyResultRef, b
if err != nil {
return nil, fmt.Errorf("invalid opManagedApplyChanges finalPlan: %w", err)
}
fallbackObj, err := unmarshalGetPrevResultOf[*states.ResourceInstanceObjectFull](prevResults, rawOperands[1])
fallbackObj, err := unmarshalGetPrevResultOf[*exec.ResourceInstanceObject](prevResults, rawOperands[1])
if err != nil {
return nil, fmt.Errorf("invalid opManagedApplyChanges fallbackObj: %w", err)
}
@ -315,7 +314,7 @@ func unmarshalOpEphemeralClose(rawOperands []uint64, prevResults []AnyResultRef,
if len(rawOperands) != 3 {
return nil, fmt.Errorf("wrong number of operands (%d) for opDataRead", len(rawOperands))
}
obj, err := unmarshalGetPrevResultOf[*states.ResourceInstanceObjectFull](prevResults, rawOperands[0])
obj, err := unmarshalGetPrevResultOf[*exec.ResourceInstanceObject](prevResults, rawOperands[0])
if err != nil {
return nil, fmt.Errorf("invalid opDataRead desiredInst: %w", err)
}

View file

@ -22,19 +22,19 @@ import (
type mockOperations struct {
Calls []mockOperationsCall
DataReadFunc func(ctx context.Context, desired *eval.DesiredResourceInstance, plannedVal cty.Value, providerClient *exec.ProviderClient) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics)
EphemeralCloseFunc func(ctx context.Context, object *states.ResourceInstanceObjectFull, providerClient *exec.ProviderClient) tfdiags.Diagnostics
EphemeralOpenFunc func(ctx context.Context, desired *eval.DesiredResourceInstance, providerClient *exec.ProviderClient) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics)
ManagedAlreadyDeposedFunc func(ctx context.Context, instAddr addrs.AbsResourceInstance, deposedKey states.DeposedKey) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics)
ManagedApplyFunc func(ctx context.Context, plan *exec.ManagedResourceObjectFinalPlan, fallback *states.ResourceInstanceObjectFull, providerClient *exec.ProviderClient) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics)
ManagedDeposeFunc func(ctx context.Context, instAddr addrs.AbsResourceInstance) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics)
ManagedFinalPlanFunc func(ctx context.Context, desired *eval.DesiredResourceInstance, prior *states.ResourceInstanceObjectFull, plannedVal cty.Value, providerClient *exec.ProviderClient) (*exec.ManagedResourceObjectFinalPlan, tfdiags.Diagnostics)
DataReadFunc func(ctx context.Context, desired *eval.DesiredResourceInstance, plannedVal cty.Value, providerClient *exec.ProviderClient) (*exec.ResourceInstanceObject, tfdiags.Diagnostics)
EphemeralCloseFunc func(ctx context.Context, object *exec.ResourceInstanceObject, providerClient *exec.ProviderClient) tfdiags.Diagnostics
EphemeralOpenFunc func(ctx context.Context, desired *eval.DesiredResourceInstance, providerClient *exec.ProviderClient) (*exec.ResourceInstanceObject, tfdiags.Diagnostics)
ManagedAlreadyDeposedFunc func(ctx context.Context, instAddr addrs.AbsResourceInstance, deposedKey states.DeposedKey) (*exec.ResourceInstanceObject, tfdiags.Diagnostics)
ManagedApplyFunc func(ctx context.Context, plan *exec.ManagedResourceObjectFinalPlan, fallback *exec.ResourceInstanceObject, providerClient *exec.ProviderClient) (*exec.ResourceInstanceObject, tfdiags.Diagnostics)
ManagedDeposeFunc func(ctx context.Context, instAddr addrs.AbsResourceInstance) (*exec.ResourceInstanceObject, tfdiags.Diagnostics)
ManagedFinalPlanFunc func(ctx context.Context, desired *eval.DesiredResourceInstance, prior *exec.ResourceInstanceObject, plannedVal cty.Value, providerClient *exec.ProviderClient) (*exec.ManagedResourceObjectFinalPlan, tfdiags.Diagnostics)
ProviderInstanceCloseFunc func(ctx context.Context, client *exec.ProviderClient) tfdiags.Diagnostics
ProviderInstanceConfigFunc func(ctx context.Context, instAddr addrs.AbsProviderInstanceCorrect) (*exec.ProviderInstanceConfig, tfdiags.Diagnostics)
ProviderInstanceOpenFunc func(ctx context.Context, config *exec.ProviderInstanceConfig) (*exec.ProviderClient, tfdiags.Diagnostics)
ResourceInstanceDesiredFunc func(ctx context.Context, instAddr addrs.AbsResourceInstance) (*eval.DesiredResourceInstance, tfdiags.Diagnostics)
ResourceInstancePostconditionsFunc func(ctx context.Context, result *states.ResourceInstanceObjectFull) tfdiags.Diagnostics
ResourceInstancePriorFunc func(ctx context.Context, instAddr addrs.AbsResourceInstance) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics)
ResourceInstancePostconditionsFunc func(ctx context.Context, result *exec.ResourceInstanceObject) tfdiags.Diagnostics
ResourceInstancePriorFunc func(ctx context.Context, instAddr addrs.AbsResourceInstance) (*exec.ResourceInstanceObject, tfdiags.Diagnostics)
mu sync.Mutex
}
@ -42,9 +42,9 @@ type mockOperations struct {
var _ exec.Operations = (*mockOperations)(nil)
// DataRead implements [exec.Operations].
func (m *mockOperations) DataRead(ctx context.Context, desired *eval.DesiredResourceInstance, plannedVal cty.Value, providerClient *exec.ProviderClient) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics) {
func (m *mockOperations) DataRead(ctx context.Context, desired *eval.DesiredResourceInstance, plannedVal cty.Value, providerClient *exec.ProviderClient) (*exec.ResourceInstanceObject, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
var result *states.ResourceInstanceObjectFull
var result *exec.ResourceInstanceObject
if m.DataReadFunc != nil {
result, diags = m.DataReadFunc(ctx, desired, plannedVal, providerClient)
}
@ -53,7 +53,7 @@ func (m *mockOperations) DataRead(ctx context.Context, desired *eval.DesiredReso
}
// EphemeralClose implements [exec.Operations].
func (m *mockOperations) EphemeralClose(ctx context.Context, object *states.ResourceInstanceObjectFull, providerClient *exec.ProviderClient) tfdiags.Diagnostics {
func (m *mockOperations) EphemeralClose(ctx context.Context, object *exec.ResourceInstanceObject, providerClient *exec.ProviderClient) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
if m.EphemeralCloseFunc != nil {
diags = m.EphemeralCloseFunc(ctx, object, providerClient)
@ -63,9 +63,9 @@ func (m *mockOperations) EphemeralClose(ctx context.Context, object *states.Reso
}
// EphemeralOpen implements [exec.Operations].
func (m *mockOperations) EphemeralOpen(ctx context.Context, desired *eval.DesiredResourceInstance, providerClient *exec.ProviderClient) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics) {
func (m *mockOperations) EphemeralOpen(ctx context.Context, desired *eval.DesiredResourceInstance, providerClient *exec.ProviderClient) (*exec.ResourceInstanceObject, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
var result *states.ResourceInstanceObjectFull
var result *exec.ResourceInstanceObject
if m.EphemeralOpenFunc != nil {
result, diags = m.EphemeralOpenFunc(ctx, desired, providerClient)
}
@ -74,9 +74,9 @@ func (m *mockOperations) EphemeralOpen(ctx context.Context, desired *eval.Desire
}
// ManagedAlreadyDeposed implements [exec.Operations].
func (m *mockOperations) ManagedAlreadyDeposed(ctx context.Context, instAddr addrs.AbsResourceInstance, deposedKey states.DeposedKey) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics) {
func (m *mockOperations) ManagedAlreadyDeposed(ctx context.Context, instAddr addrs.AbsResourceInstance, deposedKey states.DeposedKey) (*exec.ResourceInstanceObject, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
var result *states.ResourceInstanceObjectFull
var result *exec.ResourceInstanceObject
if m.ManagedAlreadyDeposedFunc != nil {
result, diags = m.ManagedAlreadyDeposedFunc(ctx, instAddr, deposedKey)
}
@ -85,9 +85,9 @@ func (m *mockOperations) ManagedAlreadyDeposed(ctx context.Context, instAddr add
}
// ManagedApply implements [exec.Operations].
func (m *mockOperations) ManagedApply(ctx context.Context, plan *exec.ManagedResourceObjectFinalPlan, fallback *states.ResourceInstanceObjectFull, providerClient *exec.ProviderClient) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics) {
func (m *mockOperations) ManagedApply(ctx context.Context, plan *exec.ManagedResourceObjectFinalPlan, fallback *exec.ResourceInstanceObject, providerClient *exec.ProviderClient) (*exec.ResourceInstanceObject, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
var result *states.ResourceInstanceObjectFull
var result *exec.ResourceInstanceObject
if m.ManagedApplyFunc != nil {
result, diags = m.ManagedApplyFunc(ctx, plan, fallback, providerClient)
}
@ -96,9 +96,9 @@ func (m *mockOperations) ManagedApply(ctx context.Context, plan *exec.ManagedRes
}
// ManagedDepose implements [exec.Operations].
func (m *mockOperations) ManagedDepose(ctx context.Context, instAddr addrs.AbsResourceInstance) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics) {
func (m *mockOperations) ManagedDepose(ctx context.Context, instAddr addrs.AbsResourceInstance) (*exec.ResourceInstanceObject, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
var result *states.ResourceInstanceObjectFull
var result *exec.ResourceInstanceObject
if m.ManagedDeposeFunc != nil {
result, diags = m.ManagedDeposeFunc(ctx, instAddr)
}
@ -107,7 +107,7 @@ func (m *mockOperations) ManagedDepose(ctx context.Context, instAddr addrs.AbsRe
}
// ManagedFinalPlan implements [exec.Operations].
func (m *mockOperations) ManagedFinalPlan(ctx context.Context, desired *eval.DesiredResourceInstance, prior *states.ResourceInstanceObjectFull, plannedVal cty.Value, providerClient *exec.ProviderClient) (*exec.ManagedResourceObjectFinalPlan, tfdiags.Diagnostics) {
func (m *mockOperations) ManagedFinalPlan(ctx context.Context, desired *eval.DesiredResourceInstance, prior *exec.ResourceInstanceObject, plannedVal cty.Value, providerClient *exec.ProviderClient) (*exec.ManagedResourceObjectFinalPlan, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
var result *exec.ManagedResourceObjectFinalPlan
if m.ManagedFinalPlanFunc != nil {
@ -161,7 +161,7 @@ func (m *mockOperations) ResourceInstanceDesired(ctx context.Context, instAddr a
}
// ResourceInstancePostconditions implements [exec.Operations].
func (m *mockOperations) ResourceInstancePostconditions(ctx context.Context, result *states.ResourceInstanceObjectFull) tfdiags.Diagnostics {
func (m *mockOperations) ResourceInstancePostconditions(ctx context.Context, result *exec.ResourceInstanceObject) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
if m.ResourceInstancePostconditionsFunc != nil {
diags = m.ResourceInstancePostconditionsFunc(ctx, result)
@ -171,9 +171,9 @@ func (m *mockOperations) ResourceInstancePostconditions(ctx context.Context, res
}
// ResourceInstancePrior implements [exec.Operations].
func (m *mockOperations) ResourceInstancePrior(ctx context.Context, instAddr addrs.AbsResourceInstance) (*states.ResourceInstanceObjectFull, tfdiags.Diagnostics) {
func (m *mockOperations) ResourceInstancePrior(ctx context.Context, instAddr addrs.AbsResourceInstance) (*exec.ResourceInstanceObject, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
var result *states.ResourceInstanceObjectFull
var result *exec.ResourceInstanceObject
if m.ResourceInstancePriorFunc != nil {
result, diags = m.ResourceInstancePriorFunc(ctx, instAddr)
}

View file

@ -9,7 +9,7 @@ import (
"github.com/zclconf/go-cty/cty"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/engine/internal/exec"
)
// ResultRef represents a result of type T that will be produced by
@ -26,7 +26,7 @@ type ResultRef[T any] interface {
// We give this its own name just because this particular result type tends
// to be named in function signatures elsewhere in the system and the
// simple name is (subjectively) easier to read than the generic name.
type ResourceInstanceResultRef = ResultRef[*states.ResourceInstanceObjectFull]
type ResourceInstanceResultRef = ResultRef[*exec.ResourceInstanceObject]
// AnyResultRef is a type-erased [ResultRef], for data
// structures that only need to represent the relationships between results

View file

@ -13,6 +13,7 @@ import (
"github.com/zclconf/go-cty/cty"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/engine/internal/exec"
"github.com/opentofu/opentofu/internal/engine/internal/execgraph"
"github.com/opentofu/opentofu/internal/lang/eval"
"github.com/opentofu/opentofu/internal/plans"
@ -279,7 +280,7 @@ func (p *planGlue) planDesiredManagedResourceInstance(ctx context.Context, inst
)
finalResultRef := egb.ManagedApply(
finalPlanRef,
execgraph.NilResultRef[*states.ResourceInstanceObjectFull](),
execgraph.NilResultRef[*exec.ResourceInstanceObject](),
providerClientRef,
)
closeProviderAfter(finalResultRef)