]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go
6ab9df7a26f8a2b6f2edb91487858ea475a11ce7
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / node_resource_refresh.go
1 package terraform
2
3 import (
4 "fmt"
5
6 "github.com/hashicorp/terraform/config"
7 "github.com/hashicorp/terraform/dag"
8 )
9
10 // NodeRefreshableManagedResource represents a resource that is expanabled into
11 // NodeRefreshableManagedResourceInstance. Resource count orphans are also added.
12 type NodeRefreshableManagedResource struct {
13 *NodeAbstractCountResource
14 }
15
16 // GraphNodeDynamicExpandable
17 func (n *NodeRefreshableManagedResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
18 // Grab the state which we read
19 state, lock := ctx.State()
20 lock.RLock()
21 defer lock.RUnlock()
22
23 // Expand the resource count which must be available by now from EvalTree
24 count, err := n.Config.Count()
25 if err != nil {
26 return nil, err
27 }
28
29 // The concrete resource factory we'll use
30 concreteResource := func(a *NodeAbstractResource) dag.Vertex {
31 // Add the config and state since we don't do that via transforms
32 a.Config = n.Config
33
34 return &NodeRefreshableManagedResourceInstance{
35 NodeAbstractResource: a,
36 }
37 }
38
39 // Start creating the steps
40 steps := []GraphTransformer{
41 // Expand the count.
42 &ResourceCountTransformer{
43 Concrete: concreteResource,
44 Count: count,
45 Addr: n.ResourceAddr(),
46 },
47
48 // Switch up any node missing state to a plannable resource. This helps
49 // catch cases where data sources depend on the counts from this resource
50 // during a scale out.
51 &ResourceRefreshPlannableTransformer{
52 State: state,
53 },
54
55 // Add the count orphans to make sure these resources are accounted for
56 // during a scale in.
57 &OrphanResourceCountTransformer{
58 Concrete: concreteResource,
59 Count: count,
60 Addr: n.ResourceAddr(),
61 State: state,
62 },
63
64 // Attach the state
65 &AttachStateTransformer{State: state},
66
67 // Targeting
68 &TargetsTransformer{ParsedTargets: n.Targets},
69
70 // Connect references so ordering is correct
71 &ReferenceTransformer{},
72
73 // Make sure there is a single root
74 &RootTransformer{},
75 }
76
77 // Build the graph
78 b := &BasicGraphBuilder{
79 Steps: steps,
80 Validate: true,
81 Name: "NodeRefreshableManagedResource",
82 }
83
84 return b.Build(ctx.Path())
85 }
86
87 // NodeRefreshableManagedResourceInstance represents a resource that is "applyable":
88 // it is ready to be applied and is represented by a diff.
89 type NodeRefreshableManagedResourceInstance struct {
90 *NodeAbstractResource
91 }
92
93 // GraphNodeDestroyer
94 func (n *NodeRefreshableManagedResourceInstance) DestroyAddr() *ResourceAddress {
95 return n.Addr
96 }
97
98 // GraphNodeEvalable
99 func (n *NodeRefreshableManagedResourceInstance) EvalTree() EvalNode {
100 // Eval info is different depending on what kind of resource this is
101 switch mode := n.Addr.Mode; mode {
102 case config.ManagedResourceMode:
103 return n.evalTreeManagedResource()
104
105 case config.DataResourceMode:
106 // Get the data source node. If we don't have a configuration
107 // then it is an orphan so we destroy it (remove it from the state).
108 var dn GraphNodeEvalable
109 if n.Config != nil {
110 dn = &NodeRefreshableDataResourceInstance{
111 NodeAbstractResource: n.NodeAbstractResource,
112 }
113 } else {
114 dn = &NodeDestroyableDataResource{
115 NodeAbstractResource: n.NodeAbstractResource,
116 }
117 }
118
119 return dn.EvalTree()
120 default:
121 panic(fmt.Errorf("unsupported resource mode %s", mode))
122 }
123 }
124
125 func (n *NodeRefreshableManagedResourceInstance) evalTreeManagedResource() EvalNode {
126 addr := n.NodeAbstractResource.Addr
127
128 // stateId is the ID to put into the state
129 stateId := addr.stateId()
130
131 // Build the instance info. More of this will be populated during eval
132 info := &InstanceInfo{
133 Id: stateId,
134 Type: addr.Type,
135 }
136
137 // Declare a bunch of variables that are used for state during
138 // evaluation. Most of this are written to by-address below.
139 var provider ResourceProvider
140 var state *InstanceState
141
142 // This happened during initial development. All known cases were
143 // fixed and tested but as a sanity check let's assert here.
144 if n.ResourceState == nil {
145 err := fmt.Errorf(
146 "No resource state attached for addr: %s\n\n"+
147 "This is a bug. Please report this to Terraform with your configuration\n"+
148 "and state attached. Please be careful to scrub any sensitive information.",
149 addr)
150 return &EvalReturnError{Error: &err}
151 }
152
153 return &EvalSequence{
154 Nodes: []EvalNode{
155 &EvalGetProvider{
156 Name: n.ProvidedBy()[0],
157 Output: &provider,
158 },
159 &EvalReadState{
160 Name: stateId,
161 Output: &state,
162 },
163 &EvalRefresh{
164 Info: info,
165 Provider: &provider,
166 State: &state,
167 Output: &state,
168 },
169 &EvalWriteState{
170 Name: stateId,
171 ResourceType: n.ResourceState.Type,
172 Provider: n.ResourceState.Provider,
173 Dependencies: n.ResourceState.Dependencies,
174 State: &state,
175 },
176 },
177 }
178 }