]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
1 | package terraform |
2 | ||
3 | import ( | |
4 | "sync" | |
5 | ||
6 | "github.com/hashicorp/terraform/config/module" | |
7 | "github.com/hashicorp/terraform/dag" | |
8 | ) | |
9 | ||
10 | // PlanGraphBuilder implements GraphBuilder and is responsible for building | |
11 | // a graph for planning (creating a Terraform Diff). | |
12 | // | |
13 | // The primary difference between this graph and others: | |
14 | // | |
15 | // * Based on the config since it represents the target state | |
16 | // | |
17 | // * Ignores lifecycle options since no lifecycle events occur here. This | |
18 | // simplifies the graph significantly since complex transforms such as | |
19 | // create-before-destroy can be completely ignored. | |
20 | // | |
21 | type PlanGraphBuilder struct { | |
22 | // Module is the root module for the graph to build. | |
23 | Module *module.Tree | |
24 | ||
25 | // State is the current state | |
26 | State *State | |
27 | ||
28 | // Providers is the list of providers supported. | |
29 | Providers []string | |
30 | ||
31 | // Provisioners is the list of provisioners supported. | |
32 | Provisioners []string | |
33 | ||
34 | // Targets are resources to target | |
35 | Targets []string | |
36 | ||
37 | // DisableReduce, if true, will not reduce the graph. Great for testing. | |
38 | DisableReduce bool | |
39 | ||
40 | // Validate will do structural validation of the graph. | |
41 | Validate bool | |
42 | ||
43 | // CustomConcrete can be set to customize the node types created | |
44 | // for various parts of the plan. This is useful in order to customize | |
45 | // the plan behavior. | |
46 | CustomConcrete bool | |
47 | ConcreteProvider ConcreteProviderNodeFunc | |
48 | ConcreteResource ConcreteResourceNodeFunc | |
49 | ConcreteResourceOrphan ConcreteResourceNodeFunc | |
50 | ||
51 | once sync.Once | |
52 | } | |
53 | ||
54 | // See GraphBuilder | |
55 | func (b *PlanGraphBuilder) Build(path []string) (*Graph, error) { | |
56 | return (&BasicGraphBuilder{ | |
57 | Steps: b.Steps(), | |
58 | Validate: b.Validate, | |
59 | Name: "PlanGraphBuilder", | |
60 | }).Build(path) | |
61 | } | |
62 | ||
63 | // See GraphBuilder | |
64 | func (b *PlanGraphBuilder) Steps() []GraphTransformer { | |
65 | b.once.Do(b.init) | |
66 | ||
67 | steps := []GraphTransformer{ | |
68 | // Creates all the resources represented in the config | |
69 | &ConfigTransformer{ | |
70 | Concrete: b.ConcreteResource, | |
71 | Module: b.Module, | |
72 | }, | |
73 | ||
74 | // Add the outputs | |
75 | &OutputTransformer{Module: b.Module}, | |
76 | ||
77 | // Add orphan resources | |
78 | &OrphanResourceTransformer{ | |
79 | Concrete: b.ConcreteResourceOrphan, | |
80 | State: b.State, | |
81 | Module: b.Module, | |
82 | }, | |
83 | ||
84 | // Attach the configuration to any resources | |
85 | &AttachResourceConfigTransformer{Module: b.Module}, | |
86 | ||
87 | // Attach the state | |
88 | &AttachStateTransformer{State: b.State}, | |
89 | ||
90 | // Add root variables | |
91 | &RootVariableTransformer{Module: b.Module}, | |
92 | ||
93 | // Create all the providers | |
94 | &MissingProviderTransformer{Providers: b.Providers, Concrete: b.ConcreteProvider}, | |
95 | &ProviderTransformer{}, | |
96 | &DisableProviderTransformer{}, | |
97 | &ParentProviderTransformer{}, | |
98 | &AttachProviderConfigTransformer{Module: b.Module}, | |
99 | ||
100 | // Provisioner-related transformations. Only add these if requested. | |
101 | GraphTransformIf( | |
102 | func() bool { return b.Provisioners != nil }, | |
103 | GraphTransformMulti( | |
104 | &MissingProvisionerTransformer{Provisioners: b.Provisioners}, | |
105 | &ProvisionerTransformer{}, | |
106 | ), | |
107 | ), | |
108 | ||
109 | // Add module variables | |
110 | &ModuleVariableTransformer{Module: b.Module}, | |
111 | ||
112 | // Connect so that the references are ready for targeting. We'll | |
113 | // have to connect again later for providers and so on. | |
114 | &ReferenceTransformer{}, | |
115 | ||
116 | // Add the node to fix the state count boundaries | |
117 | &CountBoundaryTransformer{}, | |
118 | ||
119 | // Target | |
c680a8e1 RS |
120 | &TargetsTransformer{ |
121 | Targets: b.Targets, | |
122 | ||
123 | // Resource nodes from config have not yet been expanded for | |
124 | // "count", so we must apply targeting without indices. Exact | |
125 | // targeting will be dealt with later when these resources | |
126 | // DynamicExpand. | |
127 | IgnoreIndices: true, | |
128 | }, | |
bae9f6d2 JC |
129 | |
130 | // Close opened plugin connections | |
131 | &CloseProviderTransformer{}, | |
132 | &CloseProvisionerTransformer{}, | |
133 | ||
134 | // Single root | |
135 | &RootTransformer{}, | |
136 | } | |
137 | ||
138 | if !b.DisableReduce { | |
139 | // Perform the transitive reduction to make our graph a bit | |
140 | // more sane if possible (it usually is possible). | |
141 | steps = append(steps, &TransitiveReductionTransformer{}) | |
142 | } | |
143 | ||
144 | return steps | |
145 | } | |
146 | ||
147 | func (b *PlanGraphBuilder) init() { | |
148 | // Do nothing if the user requests customizing the fields | |
149 | if b.CustomConcrete { | |
150 | return | |
151 | } | |
152 | ||
153 | b.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex { | |
154 | return &NodeApplyableProvider{ | |
155 | NodeAbstractProvider: a, | |
156 | } | |
157 | } | |
158 | ||
159 | b.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex { | |
160 | return &NodePlannableResource{ | |
161 | NodeAbstractCountResource: &NodeAbstractCountResource{ | |
162 | NodeAbstractResource: a, | |
163 | }, | |
164 | } | |
165 | } | |
166 | ||
167 | b.ConcreteResourceOrphan = func(a *NodeAbstractResource) dag.Vertex { | |
168 | return &NodePlannableResourceOrphan{ | |
169 | NodeAbstractResource: a, | |
170 | } | |
171 | } | |
172 | } |