forked from hashicorp/terraform
/
node_resource_plan.go
105 lines (86 loc) · 2.61 KB
/
node_resource_plan.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package terraform
import (
"github.com/hashicorp/terraform/dag"
)
// NodePlannableResource represents a resource that is "plannable":
// it is ready to be planned in order to create a diff.
type NodePlannableResource struct {
*NodeAbstractResource
// Set by GraphNodeTargetable and used during DynamicExpand to
// forward targets downwards.
targets []ResourceAddress
}
// GraphNodeTargetable
func (n *NodePlannableResource) SetTargets(targets []ResourceAddress) {
n.targets = targets
}
// GraphNodeEvalable
func (n *NodePlannableResource) EvalTree() EvalNode {
return &EvalSequence{
Nodes: []EvalNode{
// The EvalTree for a plannable resource primarily involves
// interpolating the count since it can contain variables
// we only just received access to.
//
// With the interpolated count, we can then DynamicExpand
// into the proper number of instances.
&EvalInterpolate{Config: n.Config.RawCount},
&EvalCountFixZeroOneBoundary{Resource: n.Config},
},
}
}
// GraphNodeDynamicExpandable
func (n *NodePlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
// Grab the state which we read
state, lock := ctx.State()
lock.RLock()
defer lock.RUnlock()
// Expand the resource count which must be available by now from EvalTree
count, err := n.Config.Count()
if err != nil {
return nil, err
}
// The concrete resource factory we'll use
concreteResource := func(a *NodeAbstractResource) dag.Vertex {
// Add the config and state since we don't do that via transforms
a.Config = n.Config
return &NodePlannableResourceInstance{
NodeAbstractResource: a,
}
}
// The concrete resource factory we'll use for oprhans
concreteResourceOrphan := func(a *NodeAbstractResource) dag.Vertex {
// Add the config and state since we don't do that via transforms
a.Config = n.Config
return &NodePlannableResourceOrphan{
NodeAbstractResource: a,
}
}
// Start creating the steps
steps := []GraphTransformer{
// Expand the count.
&ResourceCountTransformer{
Concrete: concreteResource,
Count: count,
Addr: n.ResourceAddr(),
},
// Add the count orphans
&OrphanResourceCountTransformer{
Concrete: concreteResourceOrphan,
Count: count,
Addr: n.ResourceAddr(),
State: state,
},
// Attach the state
&AttachStateTransformer{State: state},
// Targeting
&TargetsTransformer{ParsedTargets: n.targets},
// Connect references so ordering is correct
&ReferenceTransformer{},
// Make sure there is a single root
&RootTransformer{},
}
// Build the graph
b := &BasicGraphBuilder{Steps: steps, Validate: true}
return b.Build(ctx.Path())
}