]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/terraform/graph.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / graph.go
1 package terraform
2
3 import (
4 "fmt"
5 "log"
6
7 "github.com/hashicorp/terraform/tfdiags"
8
9 "github.com/hashicorp/terraform/addrs"
10
11 "github.com/hashicorp/terraform/dag"
12 )
13
14 // Graph represents the graph that Terraform uses to represent resources
15 // and their dependencies.
16 type Graph struct {
17 // Graph is the actual DAG. This is embedded so you can call the DAG
18 // methods directly.
19 dag.AcyclicGraph
20
21 // Path is the path in the module tree that this Graph represents.
22 Path addrs.ModuleInstance
23
24 // debugName is a name for reference in the debug output. This is usually
25 // to indicate what topmost builder was, and if this graph is a shadow or
26 // not.
27 debugName string
28 }
29
30 func (g *Graph) DirectedGraph() dag.Grapher {
31 return &g.AcyclicGraph
32 }
33
34 // Walk walks the graph with the given walker for callbacks. The graph
35 // will be walked with full parallelism, so the walker should expect
36 // to be called in concurrently.
37 func (g *Graph) Walk(walker GraphWalker) tfdiags.Diagnostics {
38 return g.walk(walker)
39 }
40
41 func (g *Graph) walk(walker GraphWalker) tfdiags.Diagnostics {
42 // The callbacks for enter/exiting a graph
43 ctx := walker.EnterPath(g.Path)
44 defer walker.ExitPath(g.Path)
45
46 // Get the path for logs
47 path := ctx.Path().String()
48
49 debugName := "walk-graph.json"
50 if g.debugName != "" {
51 debugName = g.debugName + "-" + debugName
52 }
53
54 // Walk the graph.
55 var walkFn dag.WalkFunc
56 walkFn = func(v dag.Vertex) (diags tfdiags.Diagnostics) {
57 log.Printf("[TRACE] vertex %q: starting visit (%T)", dag.VertexName(v), v)
58 g.DebugVisitInfo(v, g.debugName)
59
60 defer func() {
61 log.Printf("[TRACE] vertex %q: visit complete", dag.VertexName(v))
62 }()
63
64 walker.EnterVertex(v)
65 defer walker.ExitVertex(v, diags)
66
67 // vertexCtx is the context that we use when evaluating. This
68 // is normally the context of our graph but can be overridden
69 // with a GraphNodeSubPath impl.
70 vertexCtx := ctx
71 if pn, ok := v.(GraphNodeSubPath); ok && len(pn.Path()) > 0 {
72 vertexCtx = walker.EnterPath(pn.Path())
73 defer walker.ExitPath(pn.Path())
74 }
75
76 // If the node is eval-able, then evaluate it.
77 if ev, ok := v.(GraphNodeEvalable); ok {
78 tree := ev.EvalTree()
79 if tree == nil {
80 panic(fmt.Sprintf("%q (%T): nil eval tree", dag.VertexName(v), v))
81 }
82
83 // Allow the walker to change our tree if needed. Eval,
84 // then callback with the output.
85 log.Printf("[TRACE] vertex %q: evaluating", dag.VertexName(v))
86
87 g.DebugVertexInfo(v, fmt.Sprintf("evaluating %T(%s)", v, path))
88
89 tree = walker.EnterEvalTree(v, tree)
90 output, err := Eval(tree, vertexCtx)
91 diags = diags.Append(walker.ExitEvalTree(v, output, err))
92 if diags.HasErrors() {
93 return
94 }
95 }
96
97 // If the node is dynamically expanded, then expand it
98 if ev, ok := v.(GraphNodeDynamicExpandable); ok {
99 log.Printf("[TRACE] vertex %q: expanding dynamic subgraph", dag.VertexName(v))
100
101 g.DebugVertexInfo(v, fmt.Sprintf("expanding %T(%s)", v, path))
102
103 g, err := ev.DynamicExpand(vertexCtx)
104 if err != nil {
105 diags = diags.Append(err)
106 return
107 }
108 if g != nil {
109 // Walk the subgraph
110 log.Printf("[TRACE] vertex %q: entering dynamic subgraph", dag.VertexName(v))
111 subDiags := g.walk(walker)
112 diags = diags.Append(subDiags)
113 if subDiags.HasErrors() {
114 log.Printf("[TRACE] vertex %q: dynamic subgraph encountered errors", dag.VertexName(v))
115 return
116 }
117 log.Printf("[TRACE] vertex %q: dynamic subgraph completed successfully", dag.VertexName(v))
118 } else {
119 log.Printf("[TRACE] vertex %q: produced no dynamic subgraph", dag.VertexName(v))
120 }
121 }
122
123 // If the node has a subgraph, then walk the subgraph
124 if sn, ok := v.(GraphNodeSubgraph); ok {
125 log.Printf("[TRACE] vertex %q: entering static subgraph", dag.VertexName(v))
126
127 g.DebugVertexInfo(v, fmt.Sprintf("subgraph: %T(%s)", v, path))
128
129 subDiags := sn.Subgraph().(*Graph).walk(walker)
130 if subDiags.HasErrors() {
131 log.Printf("[TRACE] vertex %q: static subgraph encountered errors", dag.VertexName(v))
132 return
133 }
134 log.Printf("[TRACE] vertex %q: static subgraph completed successfully", dag.VertexName(v))
135 }
136
137 return
138 }
139
140 return g.AcyclicGraph.Walk(walkFn)
141 }