4 "github.com/hashicorp/terraform/dag"
7 // NodeRefreshableDataResource represents a resource that is "plannable":
8 // it is ready to be planned in order to create a diff.
9 type NodeRefreshableDataResource struct {
10 *NodeAbstractCountResource
13 // GraphNodeDynamicExpandable
14 func (n *NodeRefreshableDataResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
15 // Grab the state which we read
16 state, lock := ctx.State()
20 // Expand the resource count which must be available by now from EvalTree
21 count, err := n.Config.Count()
26 // The concrete resource factory we'll use
27 concreteResource := func(a *NodeAbstractResource) dag.Vertex {
28 // Add the config and state since we don't do that via transforms
31 return &NodeRefreshableDataResourceInstance{
32 NodeAbstractResource: a,
36 // We also need a destroyable resource for orphans that are a result of a
38 concreteResourceDestroyable := func(a *NodeAbstractResource) dag.Vertex {
39 // Add the config since we don't do that via transforms
42 return &NodeDestroyableDataResource{
43 NodeAbstractResource: a,
47 // Start creating the steps
48 steps := []GraphTransformer{
50 &ResourceCountTransformer{
51 Concrete: concreteResource,
53 Addr: n.ResourceAddr(),
56 // Add the count orphans. As these are orphaned refresh nodes, we add them
57 // directly as NodeDestroyableDataResource.
58 &OrphanResourceCountTransformer{
59 Concrete: concreteResourceDestroyable,
61 Addr: n.ResourceAddr(),
66 &AttachStateTransformer{State: state},
69 &TargetsTransformer{ParsedTargets: n.Targets},
71 // Connect references so ordering is correct
72 &ReferenceTransformer{},
74 // Make sure there is a single root
79 b := &BasicGraphBuilder{
82 Name: "NodeRefreshableDataResource",
85 return b.Build(ctx.Path())
88 // NodeRefreshableDataResourceInstance represents a _single_ resource instance
89 // that is refreshable.
90 type NodeRefreshableDataResourceInstance struct {
95 func (n *NodeRefreshableDataResourceInstance) EvalTree() EvalNode {
96 addr := n.NodeAbstractResource.Addr
98 // stateId is the ID to put into the state
99 stateId := addr.stateId()
101 // Build the instance info. More of this will be populated during eval
102 info := &InstanceInfo{
107 // Get the state if we have it, if not we build it
108 rs := n.ResourceState
110 rs = &ResourceState{}
113 // If the config isn't empty we update the state
117 Provider: n.Config.Provider,
118 Dependencies: n.StateReferences(),
122 // Build the resource for eval
123 resource := &Resource{
126 CountIndex: addr.Index,
128 if resource.CountIndex < 0 {
129 resource.CountIndex = 0
132 // Declare a bunch of variables that are used for state during
133 // evaluation. Most of this are written to by-address below.
134 var config *ResourceConfig
135 var diff *InstanceDiff
136 var provider ResourceProvider
137 var state *InstanceState
139 return &EvalSequence{
141 // Always destroy the existing state first, since we must
142 // make sure that values from a previous read will not
143 // get interpolated if we end up needing to defer our
144 // loading until apply time.
147 ResourceType: rs.Type,
148 Provider: rs.Provider,
149 Dependencies: rs.Dependencies,
150 State: &state, // state is nil here
154 Config: n.Config.RawConfig.Copy(),
159 // The rest of this pass can proceed only if there are no
160 // computed values in our config.
161 // (If there are, we'll deal with this during the plan and
164 If: func(ctx EvalContext) (bool, error) {
165 if config.ComputedKeys != nil && len(config.ComputedKeys) > 0 {
166 return true, EvalEarlyExitError{}
169 // If the config explicitly has a depends_on for this
170 // data source, assume the intention is to prevent
171 // refreshing ahead of that dependency.
172 if len(n.Config.DependsOn) > 0 {
173 return true, EvalEarlyExitError{}
182 // The remainder of this pass is the same as running
183 // a "plan" pass immediately followed by an "apply" pass,
184 // populating the state early so it'll be available to
185 // provider configurations that need this data during
188 Name: n.ProvidedBy()[0],
209 ResourceType: rs.Type,
210 Provider: rs.Provider,
211 Dependencies: rs.Dependencies,
215 &EvalUpdateStateHook{},