]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / node_resource_refresh.go
CommitLineData
bae9f6d2
JC
1package terraform
2
3import (
4 "fmt"
107c1cdb 5 "log"
bae9f6d2 6
107c1cdb
ND
7 "github.com/hashicorp/terraform/plans"
8 "github.com/hashicorp/terraform/providers"
9
10 "github.com/hashicorp/terraform/states"
11
12 "github.com/hashicorp/terraform/addrs"
9b12e4fe 13 "github.com/hashicorp/terraform/dag"
107c1cdb 14 "github.com/hashicorp/terraform/tfdiags"
bae9f6d2
JC
15)
16
9b12e4fe
JC
17// NodeRefreshableManagedResource represents a resource that is expanabled into
18// NodeRefreshableManagedResourceInstance. Resource count orphans are also added.
19type NodeRefreshableManagedResource struct {
107c1cdb 20 *NodeAbstractResource
9b12e4fe
JC
21}
22
107c1cdb
ND
23var (
24 _ GraphNodeSubPath = (*NodeRefreshableManagedResource)(nil)
25 _ GraphNodeDynamicExpandable = (*NodeRefreshableManagedResource)(nil)
26 _ GraphNodeReferenceable = (*NodeRefreshableManagedResource)(nil)
27 _ GraphNodeReferencer = (*NodeRefreshableManagedResource)(nil)
28 _ GraphNodeResource = (*NodeRefreshableManagedResource)(nil)
29 _ GraphNodeAttachResourceConfig = (*NodeRefreshableManagedResource)(nil)
30)
31
9b12e4fe
JC
32// GraphNodeDynamicExpandable
33func (n *NodeRefreshableManagedResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
107c1cdb
ND
34 var diags tfdiags.Diagnostics
35
36 count, countDiags := evaluateResourceCountExpression(n.Config.Count, ctx)
37 diags = diags.Append(countDiags)
38 if countDiags.HasErrors() {
39 return nil, diags.Err()
9b12e4fe
JC
40 }
41
107c1cdb
ND
42 // Next we need to potentially rename an instance address in the state
43 // if we're transitioning whether "count" is set at all.
44 fixResourceCountSetTransition(ctx, n.ResourceAddr(), count != -1)
45
46 // Our graph transformers require access to the full state, so we'll
47 // temporarily lock it while we work on this.
48 state := ctx.State().Lock()
49 defer ctx.State().Unlock()
50
9b12e4fe 51 // The concrete resource factory we'll use
107c1cdb 52 concreteResource := func(a *NodeAbstractResourceInstance) dag.Vertex {
9b12e4fe
JC
53 // Add the config and state since we don't do that via transforms
54 a.Config = n.Config
15c0b25d 55 a.ResolvedProvider = n.ResolvedProvider
9b12e4fe
JC
56
57 return &NodeRefreshableManagedResourceInstance{
107c1cdb 58 NodeAbstractResourceInstance: a,
9b12e4fe
JC
59 }
60 }
61
62 // Start creating the steps
63 steps := []GraphTransformer{
64 // Expand the count.
65 &ResourceCountTransformer{
66 Concrete: concreteResource,
107c1cdb 67 Schema: n.Schema,
9b12e4fe
JC
68 Count: count,
69 Addr: n.ResourceAddr(),
70 },
71
9b12e4fe
JC
72 // Add the count orphans to make sure these resources are accounted for
73 // during a scale in.
74 &OrphanResourceCountTransformer{
75 Concrete: concreteResource,
76 Count: count,
77 Addr: n.ResourceAddr(),
78 State: state,
79 },
80
81 // Attach the state
82 &AttachStateTransformer{State: state},
83
84 // Targeting
107c1cdb 85 &TargetsTransformer{Targets: n.Targets},
9b12e4fe
JC
86
87 // Connect references so ordering is correct
88 &ReferenceTransformer{},
89
90 // Make sure there is a single root
91 &RootTransformer{},
92 }
93
94 // Build the graph
95 b := &BasicGraphBuilder{
96 Steps: steps,
97 Validate: true,
98 Name: "NodeRefreshableManagedResource",
99 }
100
107c1cdb
ND
101 graph, diags := b.Build(ctx.Path())
102 return graph, diags.ErrWithWarnings()
9b12e4fe
JC
103}
104
105// NodeRefreshableManagedResourceInstance represents a resource that is "applyable":
bae9f6d2 106// it is ready to be applied and is represented by a diff.
9b12e4fe 107type NodeRefreshableManagedResourceInstance struct {
107c1cdb 108 *NodeAbstractResourceInstance
bae9f6d2
JC
109}
110
107c1cdb
ND
111var (
112 _ GraphNodeSubPath = (*NodeRefreshableManagedResourceInstance)(nil)
113 _ GraphNodeReferenceable = (*NodeRefreshableManagedResourceInstance)(nil)
114 _ GraphNodeReferencer = (*NodeRefreshableManagedResourceInstance)(nil)
115 _ GraphNodeDestroyer = (*NodeRefreshableManagedResourceInstance)(nil)
116 _ GraphNodeResource = (*NodeRefreshableManagedResourceInstance)(nil)
117 _ GraphNodeResourceInstance = (*NodeRefreshableManagedResourceInstance)(nil)
118 _ GraphNodeAttachResourceConfig = (*NodeRefreshableManagedResourceInstance)(nil)
119 _ GraphNodeAttachResourceState = (*NodeRefreshableManagedResourceInstance)(nil)
120 _ GraphNodeEvalable = (*NodeRefreshableManagedResourceInstance)(nil)
121)
122
bae9f6d2 123// GraphNodeDestroyer
107c1cdb
ND
124func (n *NodeRefreshableManagedResourceInstance) DestroyAddr() *addrs.AbsResourceInstance {
125 addr := n.ResourceInstanceAddr()
126 return &addr
bae9f6d2
JC
127}
128
129// GraphNodeEvalable
9b12e4fe 130func (n *NodeRefreshableManagedResourceInstance) EvalTree() EvalNode {
107c1cdb
ND
131 addr := n.ResourceInstanceAddr()
132
bae9f6d2 133 // Eval info is different depending on what kind of resource this is
107c1cdb
ND
134 switch addr.Resource.Resource.Mode {
135 case addrs.ManagedResourceMode:
c680a8e1 136 if n.ResourceState == nil {
107c1cdb 137 log.Printf("[TRACE] NodeRefreshableManagedResourceInstance: %s has no existing state to refresh", addr)
c680a8e1
RS
138 return n.evalTreeManagedResourceNoState()
139 }
107c1cdb 140 log.Printf("[TRACE] NodeRefreshableManagedResourceInstance: %s will be refreshed", addr)
bae9f6d2
JC
141 return n.evalTreeManagedResource()
142
107c1cdb 143 case addrs.DataResourceMode:
bae9f6d2
JC
144 // Get the data source node. If we don't have a configuration
145 // then it is an orphan so we destroy it (remove it from the state).
146 var dn GraphNodeEvalable
147 if n.Config != nil {
148 dn = &NodeRefreshableDataResourceInstance{
107c1cdb 149 NodeAbstractResourceInstance: n.NodeAbstractResourceInstance,
bae9f6d2
JC
150 }
151 } else {
107c1cdb
ND
152 dn = &NodeDestroyableDataResourceInstance{
153 NodeAbstractResourceInstance: n.NodeAbstractResourceInstance,
bae9f6d2
JC
154 }
155 }
156
157 return dn.EvalTree()
158 default:
107c1cdb 159 panic(fmt.Errorf("unsupported resource mode %s", addr.Resource.Resource.Mode))
bae9f6d2
JC
160 }
161}
162
9b12e4fe 163func (n *NodeRefreshableManagedResourceInstance) evalTreeManagedResource() EvalNode {
107c1cdb 164 addr := n.ResourceInstanceAddr()
bae9f6d2
JC
165
166 // Declare a bunch of variables that are used for state during
167 // evaluation. Most of this are written to by-address below.
107c1cdb
ND
168 var provider providers.Interface
169 var providerSchema *ProviderSchema
170 var state *states.ResourceInstanceObject
bae9f6d2
JC
171
172 // This happened during initial development. All known cases were
173 // fixed and tested but as a sanity check let's assert here.
174 if n.ResourceState == nil {
175 err := fmt.Errorf(
176 "No resource state attached for addr: %s\n\n"+
177 "This is a bug. Please report this to Terraform with your configuration\n"+
178 "and state attached. Please be careful to scrub any sensitive information.",
179 addr)
180 return &EvalReturnError{Error: &err}
181 }
182
183 return &EvalSequence{
184 Nodes: []EvalNode{
185 &EvalGetProvider{
107c1cdb 186 Addr: n.ResolvedProvider,
bae9f6d2 187 Output: &provider,
107c1cdb 188 Schema: &providerSchema,
bae9f6d2 189 },
107c1cdb 190
bae9f6d2 191 &EvalReadState{
107c1cdb
ND
192 Addr: addr.Resource,
193 Provider: &provider,
194 ProviderSchema: &providerSchema,
195
bae9f6d2
JC
196 Output: &state,
197 },
107c1cdb 198
bae9f6d2 199 &EvalRefresh{
107c1cdb
ND
200 Addr: addr.Resource,
201 ProviderAddr: n.ResolvedProvider,
202 Provider: &provider,
203 ProviderSchema: &providerSchema,
204 State: &state,
205 Output: &state,
bae9f6d2 206 },
107c1cdb 207
bae9f6d2 208 &EvalWriteState{
107c1cdb
ND
209 Addr: addr.Resource,
210 ProviderAddr: n.ResolvedProvider,
211 ProviderSchema: &providerSchema,
212 State: &state,
bae9f6d2
JC
213 },
214 },
215 }
216}
c680a8e1
RS
217
218// evalTreeManagedResourceNoState produces an EvalSequence for refresh resource
219// nodes that don't have state attached. An example of where this functionality
220// is useful is when a resource that already exists in state is being scaled
221// out, ie: has its resource count increased. In this case, the scaled out node
222// needs to be available to other nodes (namely data sources) that may depend
223// on it for proper interpolation, or confusing "index out of range" errors can
224// occur.
225//
226// The steps in this sequence are very similar to the steps carried out in
227// plan, but nothing is done with the diff after it is created - it is dropped,
228// and its changes are not counted in the UI.
229func (n *NodeRefreshableManagedResourceInstance) evalTreeManagedResourceNoState() EvalNode {
107c1cdb
ND
230 addr := n.ResourceInstanceAddr()
231
c680a8e1
RS
232 // Declare a bunch of variables that are used for state during
233 // evaluation. Most of this are written to by-address below.
107c1cdb
ND
234 var provider providers.Interface
235 var providerSchema *ProviderSchema
236 var change *plans.ResourceInstanceChange
237 var state *states.ResourceInstanceObject
15c0b25d 238
c680a8e1
RS
239 return &EvalSequence{
240 Nodes: []EvalNode{
c680a8e1 241 &EvalGetProvider{
107c1cdb 242 Addr: n.ResolvedProvider,
c680a8e1 243 Output: &provider,
107c1cdb 244 Schema: &providerSchema,
c680a8e1 245 },
107c1cdb 246
c680a8e1 247 &EvalReadState{
107c1cdb
ND
248 Addr: addr.Resource,
249 Provider: &provider,
250 ProviderSchema: &providerSchema,
251
c680a8e1
RS
252 Output: &state,
253 },
107c1cdb 254
c680a8e1 255 &EvalDiff{
107c1cdb
ND
256 Addr: addr.Resource,
257 Config: n.Config,
258 Provider: &provider,
259 ProviderAddr: n.ResolvedProvider,
260 ProviderSchema: &providerSchema,
261 State: &state,
262 OutputChange: &change,
263 OutputState: &state,
264 Stub: true,
c680a8e1 265 },
107c1cdb 266
c680a8e1 267 &EvalWriteState{
107c1cdb
ND
268 Addr: addr.Resource,
269 ProviderAddr: n.ResolvedProvider,
270 ProviderSchema: &providerSchema,
271 State: &state,
272 },
273
274 // We must also save the planned change, so that expressions in
275 // other nodes, such as provider configurations and data resources,
276 // can work with the planned new value.
277 //
278 // This depends on the fact that Context.Refresh creates a
279 // temporary new empty changeset for the duration of its graph
280 // walk, and so this recorded change will be discarded immediately
281 // after the refresh walk completes.
282 &EvalWriteDiff{
283 Addr: addr.Resource,
284 Change: &change,
285 ProviderSchema: &providerSchema,
c680a8e1
RS
286 },
287 },
288 }
289}