mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-30 10:47:14 -06:00
1523504645
This enables the shadow graph since all tests pass! We also change the destroy node to check the resource type using the addr since that is always available and reliable. The configuration can be nil for orphans.
195 lines
4.1 KiB
Go
195 lines
4.1 KiB
Go
package terraform
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/hashicorp/terraform/config"
|
|
)
|
|
|
|
// NodeDestroyResource represents a resource that is to be destroyed.
|
|
type NodeDestroyResource struct {
|
|
*NodeAbstractResource
|
|
}
|
|
|
|
func (n *NodeDestroyResource) Name() string {
|
|
return n.NodeAbstractResource.Name() + " (destroy)"
|
|
}
|
|
|
|
// GraphNodeDestroyer
|
|
func (n *NodeDestroyResource) DestroyAddr() *ResourceAddress {
|
|
return n.Addr
|
|
}
|
|
|
|
// GraphNodeDestroyerCBD
|
|
func (n *NodeDestroyResource) CreateBeforeDestroy() bool {
|
|
// If we have no config, we just assume no
|
|
if n.Config == nil {
|
|
return false
|
|
}
|
|
|
|
return n.Config.Lifecycle.CreateBeforeDestroy
|
|
}
|
|
|
|
// GraphNodeReferenceable, overriding NodeAbstractResource
|
|
func (n *NodeDestroyResource) ReferenceableName() []string {
|
|
result := n.NodeAbstractResource.ReferenceableName()
|
|
for i, v := range result {
|
|
result[i] = v + ".destroy"
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// GraphNodeReferencer, overriding NodeAbstractResource
|
|
func (n *NodeDestroyResource) References() []string {
|
|
return nil
|
|
}
|
|
|
|
// GraphNodeDynamicExpandable
|
|
func (n *NodeDestroyResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
|
|
// If we have no config we do nothing
|
|
if n.Config == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
state, lock := ctx.State()
|
|
lock.RLock()
|
|
defer lock.RUnlock()
|
|
|
|
// Start creating the steps
|
|
steps := make([]GraphTransformer, 0, 5)
|
|
|
|
// We want deposed resources in the state to be destroyed
|
|
steps = append(steps, &DeposedTransformer{
|
|
State: state,
|
|
View: n.Config.Id(),
|
|
})
|
|
|
|
// Target
|
|
steps = append(steps, &TargetsTransformer{
|
|
ParsedTargets: n.Targets,
|
|
})
|
|
|
|
// Always end with the root being added
|
|
steps = append(steps, &RootTransformer{})
|
|
|
|
// Build the graph
|
|
b := &BasicGraphBuilder{Steps: steps}
|
|
return b.Build(ctx.Path())
|
|
}
|
|
|
|
// GraphNodeEvalable
|
|
func (n *NodeDestroyResource) EvalTree() EvalNode {
|
|
// stateId is the ID to put into the state
|
|
stateId := n.Addr.stateId()
|
|
if n.Addr.Index > -1 {
|
|
stateId = fmt.Sprintf("%s.%d", stateId, n.Addr.Index)
|
|
}
|
|
|
|
// Build the instance info. More of this will be populated during eval
|
|
info := &InstanceInfo{
|
|
Id: stateId,
|
|
Type: n.Addr.Type,
|
|
uniqueExtra: "destroy",
|
|
}
|
|
|
|
// Get our state
|
|
rs := n.ResourceState
|
|
if rs == nil {
|
|
rs = &ResourceState{}
|
|
}
|
|
|
|
var diffApply *InstanceDiff
|
|
var provider ResourceProvider
|
|
var state *InstanceState
|
|
var err error
|
|
return &EvalOpFilter{
|
|
Ops: []walkOperation{walkApply, walkDestroy},
|
|
Node: &EvalSequence{
|
|
Nodes: []EvalNode{
|
|
// Get the saved diff for apply
|
|
&EvalReadDiff{
|
|
Name: stateId,
|
|
Diff: &diffApply,
|
|
},
|
|
|
|
// Filter the diff so we only get the destroy
|
|
&EvalFilterDiff{
|
|
Diff: &diffApply,
|
|
Output: &diffApply,
|
|
Destroy: true,
|
|
},
|
|
|
|
// If we're not destroying, then compare diffs
|
|
&EvalIf{
|
|
If: func(ctx EvalContext) (bool, error) {
|
|
if diffApply != nil && diffApply.GetDestroy() {
|
|
return true, nil
|
|
}
|
|
|
|
return true, EvalEarlyExitError{}
|
|
},
|
|
Then: EvalNoop{},
|
|
},
|
|
|
|
// Load the instance info so we have the module path set
|
|
&EvalInstanceInfo{Info: info},
|
|
|
|
&EvalGetProvider{
|
|
Name: n.ProvidedBy()[0],
|
|
Output: &provider,
|
|
},
|
|
&EvalReadState{
|
|
Name: stateId,
|
|
Output: &state,
|
|
},
|
|
&EvalRequireState{
|
|
State: &state,
|
|
},
|
|
// Make sure we handle data sources properly.
|
|
&EvalIf{
|
|
If: func(ctx EvalContext) (bool, error) {
|
|
if n.Addr == nil {
|
|
return false, fmt.Errorf("nil address")
|
|
}
|
|
|
|
if n.Addr.Mode == config.DataResourceMode {
|
|
return true, nil
|
|
}
|
|
|
|
return false, nil
|
|
},
|
|
|
|
Then: &EvalReadDataApply{
|
|
Info: info,
|
|
Diff: &diffApply,
|
|
Provider: &provider,
|
|
Output: &state,
|
|
},
|
|
Else: &EvalApply{
|
|
Info: info,
|
|
State: &state,
|
|
Diff: &diffApply,
|
|
Provider: &provider,
|
|
Output: &state,
|
|
Error: &err,
|
|
},
|
|
},
|
|
&EvalWriteState{
|
|
Name: stateId,
|
|
ResourceType: n.Addr.Type,
|
|
Provider: rs.Provider,
|
|
Dependencies: rs.Dependencies,
|
|
State: &state,
|
|
},
|
|
&EvalApplyPost{
|
|
Info: info,
|
|
State: &state,
|
|
Error: &err,
|
|
},
|
|
&EvalUpdateStateHook{},
|
|
},
|
|
},
|
|
}
|
|
}
|