]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
1 | package terraform |
2 | ||
3 | import ( | |
9b12e4fe JC |
4 | "log" |
5 | ||
107c1cdb ND |
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" | |
bae9f6d2 JC |
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 { | |
107c1cdb ND |
27 | // Config is the configuration tree. |
28 | Config *configs.Config | |
29 | ||
30 | // State is the prior state | |
31 | State *states.State | |
bae9f6d2 | 32 | |
107c1cdb ND |
33 | // Components is a factory for the plug-in components (providers and |
34 | // provisioners) available for use. | |
35 | Components contextComponentFactory | |
bae9f6d2 | 36 | |
107c1cdb ND |
37 | // Schemas is the repository of schemas we will draw from to analyse |
38 | // the configuration. | |
39 | Schemas *Schemas | |
bae9f6d2 JC |
40 | |
41 | // Targets are resources to target | |
107c1cdb | 42 | Targets []addrs.Targetable |
bae9f6d2 JC |
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 | |
107c1cdb | 52 | func (b *RefreshGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) { |
bae9f6d2 JC |
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 | ||
9b12e4fe JC |
69 | concreteManagedResource := func(a *NodeAbstractResource) dag.Vertex { |
70 | return &NodeRefreshableManagedResource{ | |
107c1cdb | 71 | NodeAbstractResource: a, |
9b12e4fe JC |
72 | } |
73 | } | |
74 | ||
107c1cdb | 75 | concreteManagedResourceInstance := func(a *NodeAbstractResourceInstance) dag.Vertex { |
9b12e4fe | 76 | return &NodeRefreshableManagedResourceInstance{ |
107c1cdb ND |
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, | |
bae9f6d2 JC |
86 | } |
87 | } | |
88 | ||
89 | concreteDataResource := func(a *NodeAbstractResource) dag.Vertex { | |
90 | return &NodeRefreshableDataResource{ | |
107c1cdb | 91 | NodeAbstractResource: a, |
bae9f6d2 JC |
92 | } |
93 | } | |
94 | ||
95 | steps := []GraphTransformer{ | |
9b12e4fe JC |
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, | |
107c1cdb | 103 | Config: b.Config, |
9b12e4fe JC |
104 | Unique: true, |
105 | ModeFilter: true, | |
107c1cdb | 106 | Mode: addrs.ManagedResourceMode, |
9b12e4fe JC |
107 | } |
108 | } | |
107c1cdb | 109 | log.Println("[TRACE] No managed resources in state during refresh; skipping managed resource transformer") |
9b12e4fe JC |
110 | return nil |
111 | }(), | |
bae9f6d2 | 112 | |
9b12e4fe JC |
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. | |
bae9f6d2 JC |
115 | &ConfigTransformer{ |
116 | Concrete: concreteDataResource, | |
107c1cdb | 117 | Config: b.Config, |
bae9f6d2 JC |
118 | Unique: true, |
119 | ModeFilter: true, | |
107c1cdb | 120 | Mode: addrs.DataResourceMode, |
bae9f6d2 JC |
121 | }, |
122 | ||
9b12e4fe JC |
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. | |
107c1cdb | 126 | &OrphanResourceInstanceTransformer{ |
9b12e4fe JC |
127 | Concrete: concreteManagedResourceInstance, |
128 | State: b.State, | |
107c1cdb ND |
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, | |
9b12e4fe JC |
139 | }, |
140 | ||
bae9f6d2 JC |
141 | // Attach the state |
142 | &AttachStateTransformer{State: b.State}, | |
143 | ||
144 | // Attach the configuration to any resources | |
107c1cdb | 145 | &AttachResourceConfigTransformer{Config: b.Config}, |
bae9f6d2 JC |
146 | |
147 | // Add root variables | |
107c1cdb | 148 | &RootVariableTransformer{Config: b.Config}, |
15c0b25d AP |
149 | |
150 | // Add the local values | |
107c1cdb | 151 | &LocalTransformer{Config: b.Config}, |
bae9f6d2 JC |
152 | |
153 | // Add the outputs | |
107c1cdb | 154 | &OutputTransformer{Config: b.Config}, |
bae9f6d2 JC |
155 | |
156 | // Add module variables | |
107c1cdb ND |
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}, | |
bae9f6d2 JC |
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 | |
c680a8e1 RS |
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 | }, | |
bae9f6d2 JC |
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 | } |