]>
Commit | Line | Data |
---|---|---|
1 | package terraform | |
2 | ||
3 | import ( | |
4 | "log" | |
5 | ||
6 | "github.com/hashicorp/terraform/states" | |
7 | "github.com/hashicorp/terraform/tfdiags" | |
8 | ||
9 | "github.com/hashicorp/terraform/addrs" | |
10 | "github.com/hashicorp/terraform/configs" | |
11 | "github.com/hashicorp/terraform/dag" | |
12 | ) | |
13 | ||
14 | // RefreshGraphBuilder implements GraphBuilder and is responsible for building | |
15 | // a graph for refreshing (updating the Terraform state). | |
16 | // | |
17 | // The primary difference between this graph and others: | |
18 | // | |
19 | // * Based on the state since it represents the only resources that | |
20 | // need to be refreshed. | |
21 | // | |
22 | // * Ignores lifecycle options since no lifecycle events occur here. This | |
23 | // simplifies the graph significantly since complex transforms such as | |
24 | // create-before-destroy can be completely ignored. | |
25 | // | |
26 | type RefreshGraphBuilder struct { | |
27 | // Config is the configuration tree. | |
28 | Config *configs.Config | |
29 | ||
30 | // State is the prior state | |
31 | State *states.State | |
32 | ||
33 | // Components is a factory for the plug-in components (providers and | |
34 | // provisioners) available for use. | |
35 | Components contextComponentFactory | |
36 | ||
37 | // Schemas is the repository of schemas we will draw from to analyse | |
38 | // the configuration. | |
39 | Schemas *Schemas | |
40 | ||
41 | // Targets are resources to target | |
42 | Targets []addrs.Targetable | |
43 | ||
44 | // DisableReduce, if true, will not reduce the graph. Great for testing. | |
45 | DisableReduce bool | |
46 | ||
47 | // Validate will do structural validation of the graph. | |
48 | Validate bool | |
49 | } | |
50 | ||
51 | // See GraphBuilder | |
52 | func (b *RefreshGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) { | |
53 | return (&BasicGraphBuilder{ | |
54 | Steps: b.Steps(), | |
55 | Validate: b.Validate, | |
56 | Name: "RefreshGraphBuilder", | |
57 | }).Build(path) | |
58 | } | |
59 | ||
60 | // See GraphBuilder | |
61 | func (b *RefreshGraphBuilder) Steps() []GraphTransformer { | |
62 | // Custom factory for creating providers. | |
63 | concreteProvider := func(a *NodeAbstractProvider) dag.Vertex { | |
64 | return &NodeApplyableProvider{ | |
65 | NodeAbstractProvider: a, | |
66 | } | |
67 | } | |
68 | ||
69 | concreteManagedResource := func(a *NodeAbstractResource) dag.Vertex { | |
70 | return &NodeRefreshableManagedResource{ | |
71 | NodeAbstractResource: a, | |
72 | } | |
73 | } | |
74 | ||
75 | concreteManagedResourceInstance := func(a *NodeAbstractResourceInstance) dag.Vertex { | |
76 | return &NodeRefreshableManagedResourceInstance{ | |
77 | NodeAbstractResourceInstance: a, | |
78 | } | |
79 | } | |
80 | ||
81 | concreteResourceInstanceDeposed := func(a *NodeAbstractResourceInstance, key states.DeposedKey) dag.Vertex { | |
82 | // The "Plan" node type also handles refreshing behavior. | |
83 | return &NodePlanDeposedResourceInstanceObject{ | |
84 | NodeAbstractResourceInstance: a, | |
85 | DeposedKey: key, | |
86 | } | |
87 | } | |
88 | ||
89 | concreteDataResource := func(a *NodeAbstractResource) dag.Vertex { | |
90 | return &NodeRefreshableDataResource{ | |
91 | NodeAbstractResource: a, | |
92 | } | |
93 | } | |
94 | ||
95 | steps := []GraphTransformer{ | |
96 | // Creates all the managed resources that aren't in the state, but only if | |
97 | // we have a state already. No resources in state means there's not | |
98 | // anything to refresh. | |
99 | func() GraphTransformer { | |
100 | if b.State.HasResources() { | |
101 | return &ConfigTransformer{ | |
102 | Concrete: concreteManagedResource, | |
103 | Config: b.Config, | |
104 | Unique: true, | |
105 | ModeFilter: true, | |
106 | Mode: addrs.ManagedResourceMode, | |
107 | } | |
108 | } | |
109 | log.Println("[TRACE] No managed resources in state during refresh; skipping managed resource transformer") | |
110 | return nil | |
111 | }(), | |
112 | ||
113 | // Creates all the data resources that aren't in the state. This will also | |
114 | // add any orphans from scaling in as destroy nodes. | |
115 | &ConfigTransformer{ | |
116 | Concrete: concreteDataResource, | |
117 | Config: b.Config, | |
118 | Unique: true, | |
119 | ModeFilter: true, | |
120 | Mode: addrs.DataResourceMode, | |
121 | }, | |
122 | ||
123 | // Add any fully-orphaned resources from config (ones that have been | |
124 | // removed completely, not ones that are just orphaned due to a scaled-in | |
125 | // count. | |
126 | &OrphanResourceInstanceTransformer{ | |
127 | Concrete: concreteManagedResourceInstance, | |
128 | State: b.State, | |
129 | Config: b.Config, | |
130 | }, | |
131 | ||
132 | // We also need nodes for any deposed instance objects present in the | |
133 | // state, so we can check if they still exist. (This intentionally | |
134 | // skips creating nodes for _current_ objects, since ConfigTransformer | |
135 | // created nodes that will do that during DynamicExpand.) | |
136 | &StateTransformer{ | |
137 | ConcreteDeposed: concreteResourceInstanceDeposed, | |
138 | State: b.State, | |
139 | }, | |
140 | ||
141 | // Attach the state | |
142 | &AttachStateTransformer{State: b.State}, | |
143 | ||
144 | // Attach the configuration to any resources | |
145 | &AttachResourceConfigTransformer{Config: b.Config}, | |
146 | ||
147 | // Add root variables | |
148 | &RootVariableTransformer{Config: b.Config}, | |
149 | ||
150 | // Add the local values | |
151 | &LocalTransformer{Config: b.Config}, | |
152 | ||
153 | // Add the outputs | |
154 | &OutputTransformer{Config: b.Config}, | |
155 | ||
156 | // Add module variables | |
157 | &ModuleVariableTransformer{Config: b.Config}, | |
158 | ||
159 | TransformProviders(b.Components.ResourceProviders(), concreteProvider, b.Config), | |
160 | ||
161 | // Must attach schemas before ReferenceTransformer so that we can | |
162 | // analyze the configuration to find references. | |
163 | &AttachSchemaTransformer{Schemas: b.Schemas}, | |
164 | ||
165 | // Connect so that the references are ready for targeting. We'll | |
166 | // have to connect again later for providers and so on. | |
167 | &ReferenceTransformer{}, | |
168 | ||
169 | // Target | |
170 | &TargetsTransformer{ | |
171 | Targets: b.Targets, | |
172 | ||
173 | // Resource nodes from config have not yet been expanded for | |
174 | // "count", so we must apply targeting without indices. Exact | |
175 | // targeting will be dealt with later when these resources | |
176 | // DynamicExpand. | |
177 | IgnoreIndices: true, | |
178 | }, | |
179 | ||
180 | // Close opened plugin connections | |
181 | &CloseProviderTransformer{}, | |
182 | ||
183 | // Single root | |
184 | &RootTransformer{}, | |
185 | } | |
186 | ||
187 | if !b.DisableReduce { | |
188 | // Perform the transitive reduction to make our graph a bit | |
189 | // more sane if possible (it usually is possible). | |
190 | steps = append(steps, &TransitiveReductionTransformer{}) | |
191 | } | |
192 | ||
193 | return steps | |
194 | } |