mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
This turned out to be a big messy commit, since the way providers are referenced is tightly coupled throughout the code. That starts to unify how providers are referenced, using the format output node Name method. Add a new field to the internal resource data types called ResolvedProvider. This is set by a new setter method SetProvider when a resource is connected to a provider during graph creation. This allows us to later lookup the provider instance a resource is connected to, without requiring it to have the same module path. The InitProvider context method now takes 2 arguments, one if the provider type and the second is the full name of the provider. While the provider type could still be parsed from the full name, this makes it more explicit and, and changes to the name format won't effect this code.
179 lines
4.1 KiB
Go
179 lines
4.1 KiB
Go
package terraform
|
|
|
|
import "fmt"
|
|
|
|
// DeposedTransformer is a GraphTransformer that adds deposed resources
|
|
// to the graph.
|
|
type DeposedTransformer struct {
|
|
// State is the global state. We'll automatically find the correct
|
|
// ModuleState based on the Graph.Path that is being transformed.
|
|
State *State
|
|
|
|
// View, if non-empty, is the ModuleState.View used around the state
|
|
// to find deposed resources.
|
|
View string
|
|
|
|
// The provider used by the resourced which were deposed
|
|
ResolvedProvider string
|
|
}
|
|
|
|
func (t *DeposedTransformer) Transform(g *Graph) error {
|
|
state := t.State.ModuleByPath(g.Path)
|
|
if state == nil {
|
|
// If there is no state for our module there can't be any deposed
|
|
// resources, since they live in the state.
|
|
return nil
|
|
}
|
|
|
|
// If we have a view, apply it now
|
|
if t.View != "" {
|
|
state = state.View(t.View)
|
|
}
|
|
|
|
// Go through all the resources in our state to look for deposed resources
|
|
for k, rs := range state.Resources {
|
|
// If we have no deposed resources, then move on
|
|
if len(rs.Deposed) == 0 {
|
|
continue
|
|
}
|
|
|
|
deposed := rs.Deposed
|
|
|
|
for i, _ := range deposed {
|
|
g.Add(&graphNodeDeposedResource{
|
|
Index: i,
|
|
ResourceName: k,
|
|
ResourceType: rs.Type,
|
|
ProviderName: rs.Provider,
|
|
ResolvedProvider: t.ResolvedProvider,
|
|
})
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// graphNodeDeposedResource is the graph vertex representing a deposed resource.
|
|
type graphNodeDeposedResource struct {
|
|
Index int
|
|
ResourceName string
|
|
ResourceType string
|
|
ProviderName string
|
|
ResolvedProvider string
|
|
}
|
|
|
|
func (n *graphNodeDeposedResource) Name() string {
|
|
return fmt.Sprintf("%s (deposed #%d)", n.ResourceName, n.Index)
|
|
}
|
|
|
|
func (n *graphNodeDeposedResource) ProvidedBy() []string {
|
|
return []string{resourceProvider(n.ResourceName, n.ProviderName)}
|
|
}
|
|
|
|
func (n *graphNodeDeposedResource) SetProvider(p string) {
|
|
n.ResolvedProvider = p
|
|
}
|
|
|
|
// GraphNodeEvalable impl.
|
|
func (n *graphNodeDeposedResource) EvalTree() EvalNode {
|
|
var provider ResourceProvider
|
|
var state *InstanceState
|
|
|
|
seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)}
|
|
|
|
// Build instance info
|
|
info := &InstanceInfo{Id: n.Name(), Type: n.ResourceType}
|
|
seq.Nodes = append(seq.Nodes, &EvalInstanceInfo{Info: info})
|
|
|
|
// Refresh the resource
|
|
seq.Nodes = append(seq.Nodes, &EvalOpFilter{
|
|
Ops: []walkOperation{walkRefresh},
|
|
Node: &EvalSequence{
|
|
Nodes: []EvalNode{
|
|
&EvalGetProvider{
|
|
Name: n.ResolvedProvider,
|
|
Output: &provider,
|
|
},
|
|
&EvalReadStateDeposed{
|
|
Name: n.ResourceName,
|
|
Output: &state,
|
|
Index: n.Index,
|
|
},
|
|
&EvalRefresh{
|
|
Info: info,
|
|
Provider: &provider,
|
|
State: &state,
|
|
Output: &state,
|
|
},
|
|
&EvalWriteStateDeposed{
|
|
Name: n.ResourceName,
|
|
ResourceType: n.ResourceType,
|
|
Provider: n.ProviderName,
|
|
State: &state,
|
|
Index: n.Index,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
// Apply
|
|
var diff *InstanceDiff
|
|
var err error
|
|
seq.Nodes = append(seq.Nodes, &EvalOpFilter{
|
|
Ops: []walkOperation{walkApply, walkDestroy},
|
|
Node: &EvalSequence{
|
|
Nodes: []EvalNode{
|
|
&EvalGetProvider{
|
|
Name: n.ResolvedProvider,
|
|
Output: &provider,
|
|
},
|
|
&EvalReadStateDeposed{
|
|
Name: n.ResourceName,
|
|
Output: &state,
|
|
Index: n.Index,
|
|
},
|
|
&EvalDiffDestroy{
|
|
Info: info,
|
|
State: &state,
|
|
Output: &diff,
|
|
},
|
|
// Call pre-apply hook
|
|
&EvalApplyPre{
|
|
Info: info,
|
|
State: &state,
|
|
Diff: &diff,
|
|
},
|
|
&EvalApply{
|
|
Info: info,
|
|
State: &state,
|
|
Diff: &diff,
|
|
Provider: &provider,
|
|
Output: &state,
|
|
Error: &err,
|
|
},
|
|
// Always write the resource back to the state deposed... if it
|
|
// was successfully destroyed it will be pruned. If it was not, it will
|
|
// be caught on the next run.
|
|
&EvalWriteStateDeposed{
|
|
Name: n.ResourceName,
|
|
ResourceType: n.ResourceType,
|
|
Provider: n.ProviderName,
|
|
State: &state,
|
|
Index: n.Index,
|
|
},
|
|
&EvalApplyPost{
|
|
Info: info,
|
|
State: &state,
|
|
Error: &err,
|
|
},
|
|
&EvalReturnError{
|
|
Error: &err,
|
|
},
|
|
&EvalUpdateStateHook{},
|
|
},
|
|
},
|
|
})
|
|
|
|
return seq
|
|
}
|