]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/terraform/transform_provider.go
Initial transfer of provider code
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / transform_provider.go
1 package terraform
2
3 import (
4 "fmt"
5 "log"
6 "strings"
7
8 "github.com/hashicorp/go-multierror"
9 "github.com/hashicorp/terraform/dag"
10 )
11
12 // GraphNodeProvider is an interface that nodes that can be a provider
13 // must implement. The ProviderName returned is the name of the provider
14 // they satisfy.
15 type GraphNodeProvider interface {
16 ProviderName() string
17 }
18
19 // GraphNodeCloseProvider is an interface that nodes that can be a close
20 // provider must implement. The CloseProviderName returned is the name of
21 // the provider they satisfy.
22 type GraphNodeCloseProvider interface {
23 CloseProviderName() string
24 }
25
26 // GraphNodeProviderConsumer is an interface that nodes that require
27 // a provider must implement. ProvidedBy must return the name of the provider
28 // to use.
29 type GraphNodeProviderConsumer interface {
30 ProvidedBy() []string
31 }
32
33 // ProviderTransformer is a GraphTransformer that maps resources to
34 // providers within the graph. This will error if there are any resources
35 // that don't map to proper resources.
36 type ProviderTransformer struct{}
37
38 func (t *ProviderTransformer) Transform(g *Graph) error {
39 // Go through the other nodes and match them to providers they need
40 var err error
41 m := providerVertexMap(g)
42 for _, v := range g.Vertices() {
43 if pv, ok := v.(GraphNodeProviderConsumer); ok {
44 for _, p := range pv.ProvidedBy() {
45 target := m[providerMapKey(p, pv)]
46 if target == nil {
47 println(fmt.Sprintf("%#v\n\n%#v", m, providerMapKey(p, pv)))
48 err = multierror.Append(err, fmt.Errorf(
49 "%s: provider %s couldn't be found",
50 dag.VertexName(v), p))
51 continue
52 }
53
54 g.Connect(dag.BasicEdge(v, target))
55 }
56 }
57 }
58
59 return err
60 }
61
62 // CloseProviderTransformer is a GraphTransformer that adds nodes to the
63 // graph that will close open provider connections that aren't needed anymore.
64 // A provider connection is not needed anymore once all depended resources
65 // in the graph are evaluated.
66 type CloseProviderTransformer struct{}
67
68 func (t *CloseProviderTransformer) Transform(g *Graph) error {
69 pm := providerVertexMap(g)
70 cpm := closeProviderVertexMap(g)
71 var err error
72 for _, v := range g.Vertices() {
73 if pv, ok := v.(GraphNodeProviderConsumer); ok {
74 for _, p := range pv.ProvidedBy() {
75 key := p
76 source := cpm[key]
77
78 if source == nil {
79 // Create a new graphNodeCloseProvider and add it to the graph
80 source = &graphNodeCloseProvider{ProviderNameValue: p}
81 g.Add(source)
82
83 // Close node needs to depend on provider
84 provider, ok := pm[key]
85 if !ok {
86 err = multierror.Append(err, fmt.Errorf(
87 "%s: provider %s couldn't be found for closing",
88 dag.VertexName(v), p))
89 continue
90 }
91 g.Connect(dag.BasicEdge(source, provider))
92
93 // Make sure we also add the new graphNodeCloseProvider to the map
94 // so we don't create and add any duplicate graphNodeCloseProviders.
95 cpm[key] = source
96 }
97
98 // Close node depends on all nodes provided by the provider
99 g.Connect(dag.BasicEdge(source, v))
100 }
101 }
102 }
103
104 return err
105 }
106
107 // MissingProviderTransformer is a GraphTransformer that adds nodes
108 // for missing providers into the graph. Specifically, it creates provider
109 // configuration nodes for all the providers that we support. These are
110 // pruned later during an optimization pass.
111 type MissingProviderTransformer struct {
112 // Providers is the list of providers we support.
113 Providers []string
114
115 // AllowAny will not check that a provider is supported before adding
116 // it to the graph.
117 AllowAny bool
118
119 // Concrete, if set, overrides how the providers are made.
120 Concrete ConcreteProviderNodeFunc
121 }
122
123 func (t *MissingProviderTransformer) Transform(g *Graph) error {
124 // Initialize factory
125 if t.Concrete == nil {
126 t.Concrete = func(a *NodeAbstractProvider) dag.Vertex {
127 return a
128 }
129 }
130
131 // Create a set of our supported providers
132 supported := make(map[string]struct{}, len(t.Providers))
133 for _, v := range t.Providers {
134 supported[v] = struct{}{}
135 }
136
137 // Get the map of providers we already have in our graph
138 m := providerVertexMap(g)
139
140 // Go through all the provider consumers and make sure we add
141 // that provider if it is missing. We use a for loop here instead
142 // of "range" since we'll modify check as we go to add more to check.
143 check := g.Vertices()
144 for i := 0; i < len(check); i++ {
145 v := check[i]
146
147 pv, ok := v.(GraphNodeProviderConsumer)
148 if !ok {
149 continue
150 }
151
152 // If this node has a subpath, then we use that as a prefix
153 // into our map to check for an existing provider.
154 var path []string
155 if sp, ok := pv.(GraphNodeSubPath); ok {
156 raw := normalizeModulePath(sp.Path())
157 if len(raw) > len(rootModulePath) {
158 path = raw
159 }
160 }
161
162 for _, p := range pv.ProvidedBy() {
163 key := providerMapKey(p, pv)
164 if _, ok := m[key]; ok {
165 // This provider already exists as a configure node
166 continue
167 }
168
169 // If the provider has an alias in it, we just want the type
170 ptype := p
171 if idx := strings.IndexRune(p, '.'); idx != -1 {
172 ptype = p[:idx]
173 }
174
175 if !t.AllowAny {
176 if _, ok := supported[ptype]; !ok {
177 // If we don't support the provider type, skip it.
178 // Validation later will catch this as an error.
179 continue
180 }
181 }
182
183 // Add the missing provider node to the graph
184 v := t.Concrete(&NodeAbstractProvider{
185 NameValue: p,
186 PathValue: path,
187 }).(dag.Vertex)
188 if len(path) > 0 {
189 // We'll need the parent provider as well, so let's
190 // add a dummy node to check to make sure that we add
191 // that parent provider.
192 check = append(check, &graphNodeProviderConsumerDummy{
193 ProviderValue: p,
194 PathValue: path[:len(path)-1],
195 })
196 }
197
198 m[key] = g.Add(v)
199 }
200 }
201
202 return nil
203 }
204
205 // ParentProviderTransformer connects provider nodes to their parents.
206 //
207 // This works by finding nodes that are both GraphNodeProviders and
208 // GraphNodeSubPath. It then connects the providers to their parent
209 // path.
210 type ParentProviderTransformer struct{}
211
212 func (t *ParentProviderTransformer) Transform(g *Graph) error {
213 // Make a mapping of path to dag.Vertex, where path is: "path.name"
214 m := make(map[string]dag.Vertex)
215
216 // Also create a map that maps a provider to its parent
217 parentMap := make(map[dag.Vertex]string)
218 for _, raw := range g.Vertices() {
219 // If it is the flat version, then make it the non-flat version.
220 // We eventually want to get rid of the flat version entirely so
221 // this is a stop-gap while it still exists.
222 var v dag.Vertex = raw
223
224 // Only care about providers
225 pn, ok := v.(GraphNodeProvider)
226 if !ok || pn.ProviderName() == "" {
227 continue
228 }
229
230 // Also require a subpath, if there is no subpath then we
231 // just totally ignore it. The expectation of this transform is
232 // that it is used with a graph builder that is already flattened.
233 var path []string
234 if pn, ok := raw.(GraphNodeSubPath); ok {
235 path = pn.Path()
236 }
237 path = normalizeModulePath(path)
238
239 // Build the key with path.name i.e. "child.subchild.aws"
240 key := fmt.Sprintf("%s.%s", strings.Join(path, "."), pn.ProviderName())
241 m[key] = raw
242
243 // Determine the parent if we're non-root. This is length 1 since
244 // the 0 index should be "root" since we normalize above.
245 if len(path) > 1 {
246 path = path[:len(path)-1]
247 key := fmt.Sprintf("%s.%s", strings.Join(path, "."), pn.ProviderName())
248 parentMap[raw] = key
249 }
250 }
251
252 // Connect!
253 for v, key := range parentMap {
254 if parent, ok := m[key]; ok {
255 g.Connect(dag.BasicEdge(v, parent))
256 }
257 }
258
259 return nil
260 }
261
262 // PruneProviderTransformer is a GraphTransformer that prunes all the
263 // providers that aren't needed from the graph. A provider is unneeded if
264 // no resource or module is using that provider.
265 type PruneProviderTransformer struct{}
266
267 func (t *PruneProviderTransformer) Transform(g *Graph) error {
268 for _, v := range g.Vertices() {
269 // We only care about the providers
270 if pn, ok := v.(GraphNodeProvider); !ok || pn.ProviderName() == "" {
271 continue
272 }
273 // Does anything depend on this? If not, then prune it.
274 if s := g.UpEdges(v); s.Len() == 0 {
275 if nv, ok := v.(dag.NamedVertex); ok {
276 log.Printf("[DEBUG] Pruning provider with no dependencies: %s", nv.Name())
277 }
278 g.Remove(v)
279 }
280 }
281
282 return nil
283 }
284
285 // providerMapKey is a helper that gives us the key to use for the
286 // maps returned by things such as providerVertexMap.
287 func providerMapKey(k string, v dag.Vertex) string {
288 pathPrefix := ""
289 if sp, ok := v.(GraphNodeSubPath); ok {
290 raw := normalizeModulePath(sp.Path())
291 if len(raw) > len(rootModulePath) {
292 pathPrefix = modulePrefixStr(raw) + "."
293 }
294 }
295
296 return pathPrefix + k
297 }
298
299 func providerVertexMap(g *Graph) map[string]dag.Vertex {
300 m := make(map[string]dag.Vertex)
301 for _, v := range g.Vertices() {
302 if pv, ok := v.(GraphNodeProvider); ok {
303 key := providerMapKey(pv.ProviderName(), v)
304 m[key] = v
305 }
306 }
307
308 return m
309 }
310
311 func closeProviderVertexMap(g *Graph) map[string]dag.Vertex {
312 m := make(map[string]dag.Vertex)
313 for _, v := range g.Vertices() {
314 if pv, ok := v.(GraphNodeCloseProvider); ok {
315 m[pv.CloseProviderName()] = v
316 }
317 }
318
319 return m
320 }
321
322 type graphNodeCloseProvider struct {
323 ProviderNameValue string
324 }
325
326 func (n *graphNodeCloseProvider) Name() string {
327 return fmt.Sprintf("provider.%s (close)", n.ProviderNameValue)
328 }
329
330 // GraphNodeEvalable impl.
331 func (n *graphNodeCloseProvider) EvalTree() EvalNode {
332 return CloseProviderEvalTree(n.ProviderNameValue)
333 }
334
335 // GraphNodeDependable impl.
336 func (n *graphNodeCloseProvider) DependableName() []string {
337 return []string{n.Name()}
338 }
339
340 func (n *graphNodeCloseProvider) CloseProviderName() string {
341 return n.ProviderNameValue
342 }
343
344 // GraphNodeDotter impl.
345 func (n *graphNodeCloseProvider) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
346 if !opts.Verbose {
347 return nil
348 }
349 return &dag.DotNode{
350 Name: name,
351 Attrs: map[string]string{
352 "label": n.Name(),
353 "shape": "diamond",
354 },
355 }
356 }
357
358 // RemovableIfNotTargeted
359 func (n *graphNodeCloseProvider) RemoveIfNotTargeted() bool {
360 // We need to add this so that this node will be removed if
361 // it isn't targeted or a dependency of a target.
362 return true
363 }
364
365 // graphNodeProviderConsumerDummy is a struct that never enters the real
366 // graph (though it could to no ill effect). It implements
367 // GraphNodeProviderConsumer and GraphNodeSubpath as a way to force
368 // certain transformations.
369 type graphNodeProviderConsumerDummy struct {
370 ProviderValue string
371 PathValue []string
372 }
373
374 func (n *graphNodeProviderConsumerDummy) Path() []string {
375 return n.PathValue
376 }
377
378 func (n *graphNodeProviderConsumerDummy) ProvidedBy() []string {
379 return []string{n.ProviderValue}
380 }