mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Data sources should not require reading the previous versions. While we previously skipped the decoding if it were to fail, this removes the need for any prior state at all. The only place where the prior state was functionally used was in the destroy path. Because a data source destroy is only for cleanup purposes to clean out the state using the same code paths as a managed resource, we can substitute the prior state in the change change with a null value to maintain the same behavior.
123 lines
4.2 KiB
Go
123 lines
4.2 KiB
Go
package terraform
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/hashicorp/terraform/internal/addrs"
|
|
"github.com/hashicorp/terraform/internal/plans"
|
|
"github.com/hashicorp/terraform/internal/states"
|
|
"github.com/hashicorp/terraform/internal/tfdiags"
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
// NodePlanDestroyableResourceInstance represents a resource that is ready
|
|
// to be planned for destruction.
|
|
type NodePlanDestroyableResourceInstance struct {
|
|
*NodeAbstractResourceInstance
|
|
|
|
// skipRefresh indicates that we should skip refreshing
|
|
skipRefresh bool
|
|
}
|
|
|
|
var (
|
|
_ GraphNodeModuleInstance = (*NodePlanDestroyableResourceInstance)(nil)
|
|
_ GraphNodeReferenceable = (*NodePlanDestroyableResourceInstance)(nil)
|
|
_ GraphNodeReferencer = (*NodePlanDestroyableResourceInstance)(nil)
|
|
_ GraphNodeDestroyer = (*NodePlanDestroyableResourceInstance)(nil)
|
|
_ GraphNodeConfigResource = (*NodePlanDestroyableResourceInstance)(nil)
|
|
_ GraphNodeResourceInstance = (*NodePlanDestroyableResourceInstance)(nil)
|
|
_ GraphNodeAttachResourceConfig = (*NodePlanDestroyableResourceInstance)(nil)
|
|
_ GraphNodeAttachResourceState = (*NodePlanDestroyableResourceInstance)(nil)
|
|
_ GraphNodeExecutable = (*NodePlanDestroyableResourceInstance)(nil)
|
|
_ GraphNodeProviderConsumer = (*NodePlanDestroyableResourceInstance)(nil)
|
|
)
|
|
|
|
// GraphNodeDestroyer
|
|
func (n *NodePlanDestroyableResourceInstance) DestroyAddr() *addrs.AbsResourceInstance {
|
|
addr := n.ResourceInstanceAddr()
|
|
return &addr
|
|
}
|
|
|
|
// GraphNodeEvalable
|
|
func (n *NodePlanDestroyableResourceInstance) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
|
addr := n.ResourceInstanceAddr()
|
|
|
|
switch addr.Resource.Resource.Mode {
|
|
case addrs.ManagedResourceMode:
|
|
return n.managedResourceExecute(ctx, op)
|
|
case addrs.DataResourceMode:
|
|
return n.dataResourceExecute(ctx, op)
|
|
default:
|
|
panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
|
|
}
|
|
}
|
|
|
|
func (n *NodePlanDestroyableResourceInstance) managedResourceExecute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
|
addr := n.ResourceInstanceAddr()
|
|
|
|
// Declare a bunch of variables that are used for state during
|
|
// evaluation. These are written to by address in the EvalNodes we
|
|
// declare below.
|
|
var change *plans.ResourceInstanceChange
|
|
var state *states.ResourceInstanceObject
|
|
|
|
state, err := n.readResourceInstanceState(ctx, addr)
|
|
diags = diags.Append(err)
|
|
if diags.HasErrors() {
|
|
return diags
|
|
}
|
|
|
|
// If we are in the "skip refresh" mode then we will have skipped over our
|
|
// usual opportunity to update the previous run state and refresh state
|
|
// with the result of any provider schema upgrades, so we'll compensate
|
|
// by doing that here.
|
|
//
|
|
// NOTE: this is coupled with logic in Context.destroyPlan which skips
|
|
// running a normal plan walk when refresh is enabled. These two
|
|
// conditionals must agree (be exactly opposite) in order to get the
|
|
// correct behavior in both cases.
|
|
if n.skipRefresh {
|
|
diags = diags.Append(n.writeResourceInstanceState(ctx, state, prevRunState))
|
|
if diags.HasErrors() {
|
|
return diags
|
|
}
|
|
diags = diags.Append(n.writeResourceInstanceState(ctx, state, refreshState))
|
|
if diags.HasErrors() {
|
|
return diags
|
|
}
|
|
}
|
|
|
|
change, destroyPlanDiags := n.planDestroy(ctx, state, "")
|
|
diags = diags.Append(destroyPlanDiags)
|
|
if diags.HasErrors() {
|
|
return diags
|
|
}
|
|
|
|
diags = diags.Append(n.checkPreventDestroy(change))
|
|
if diags.HasErrors() {
|
|
return diags
|
|
}
|
|
|
|
diags = diags.Append(n.writeChange(ctx, change, ""))
|
|
return diags
|
|
}
|
|
|
|
func (n *NodePlanDestroyableResourceInstance) dataResourceExecute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
|
|
|
// We may not be able to read a prior data source from the state if the
|
|
// schema was upgraded and we are destroying before ever refreshing that
|
|
// data source. Regardless, a data source "destroy" is simply writing a
|
|
// null state, which we can do with a null prior state too.
|
|
change := &plans.ResourceInstanceChange{
|
|
Addr: n.ResourceInstanceAddr(),
|
|
PrevRunAddr: n.prevRunAddr(ctx),
|
|
Change: plans.Change{
|
|
Action: plans.Delete,
|
|
Before: cty.NullVal(cty.DynamicPseudoType),
|
|
After: cty.NullVal(cty.DynamicPseudoType),
|
|
},
|
|
ProviderAddr: n.ResolvedProvider,
|
|
}
|
|
return diags.Append(n.writeChange(ctx, change, ""))
|
|
}
|