]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/hashicorp/terraform/terraform/transform_provisioner.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / transform_provisioner.go
CommitLineData
bae9f6d2
JC
1package terraform
2
3import (
4 "fmt"
107c1cdb
ND
5 "log"
6
7 "github.com/hashicorp/terraform/addrs"
bae9f6d2
JC
8
9 "github.com/hashicorp/go-multierror"
10 "github.com/hashicorp/terraform/dag"
11)
12
13// GraphNodeProvisioner is an interface that nodes that can be a provisioner
14// must implement. The ProvisionerName returned is the name of the provisioner
15// they satisfy.
16type GraphNodeProvisioner interface {
17 ProvisionerName() string
18}
19
20// GraphNodeCloseProvisioner is an interface that nodes that can be a close
21// provisioner must implement. The CloseProvisionerName returned is the name
22// of the provisioner they satisfy.
23type GraphNodeCloseProvisioner interface {
24 CloseProvisionerName() string
25}
26
27// GraphNodeProvisionerConsumer is an interface that nodes that require
107c1cdb
ND
28// a provisioner must implement. ProvisionedBy must return the names of the
29// provisioners to use.
bae9f6d2
JC
30type GraphNodeProvisionerConsumer interface {
31 ProvisionedBy() []string
32}
33
34// ProvisionerTransformer is a GraphTransformer that maps resources to
35// provisioners within the graph. This will error if there are any resources
36// that don't map to proper resources.
37type ProvisionerTransformer struct{}
38
39func (t *ProvisionerTransformer) Transform(g *Graph) error {
40 // Go through the other nodes and match them to provisioners they need
41 var err error
42 m := provisionerVertexMap(g)
43 for _, v := range g.Vertices() {
44 if pv, ok := v.(GraphNodeProvisionerConsumer); ok {
45 for _, p := range pv.ProvisionedBy() {
46 key := provisionerMapKey(p, pv)
47 if m[key] == nil {
48 err = multierror.Append(err, fmt.Errorf(
49 "%s: provisioner %s couldn't be found",
50 dag.VertexName(v), p))
51 continue
52 }
53
107c1cdb 54 log.Printf("[TRACE] ProvisionerTransformer: %s is provisioned by %s (%q)", dag.VertexName(v), key, dag.VertexName(m[key]))
bae9f6d2
JC
55 g.Connect(dag.BasicEdge(v, m[key]))
56 }
57 }
58 }
59
60 return err
61}
62
63// MissingProvisionerTransformer is a GraphTransformer that adds nodes
64// for missing provisioners into the graph.
65type MissingProvisionerTransformer struct {
66 // Provisioners is the list of provisioners we support.
67 Provisioners []string
68}
69
70func (t *MissingProvisionerTransformer) Transform(g *Graph) error {
71 // Create a set of our supported provisioners
72 supported := make(map[string]struct{}, len(t.Provisioners))
73 for _, v := range t.Provisioners {
74 supported[v] = struct{}{}
75 }
76
77 // Get the map of provisioners we already have in our graph
78 m := provisionerVertexMap(g)
79
80 // Go through all the provisioner consumers and make sure we add
81 // that provisioner if it is missing.
82 for _, v := range g.Vertices() {
83 pv, ok := v.(GraphNodeProvisionerConsumer)
84 if !ok {
85 continue
86 }
87
88 // If this node has a subpath, then we use that as a prefix
89 // into our map to check for an existing provider.
107c1cdb 90 path := addrs.RootModuleInstance
bae9f6d2 91 if sp, ok := pv.(GraphNodeSubPath); ok {
107c1cdb 92 path = sp.Path()
bae9f6d2
JC
93 }
94
95 for _, p := range pv.ProvisionedBy() {
96 // Build the key for storing in the map
97 key := provisionerMapKey(p, pv)
98
99 if _, ok := m[key]; ok {
100 // This provisioner already exists as a configure node
101 continue
102 }
103
104 if _, ok := supported[p]; !ok {
107c1cdb 105 // If we don't support the provisioner type, we skip it.
bae9f6d2
JC
106 // Validation later will catch this as an error.
107 continue
108 }
109
110 // Build the vertex
111 var newV dag.Vertex = &NodeProvisioner{
112 NameValue: p,
113 PathValue: path,
114 }
115
116 // Add the missing provisioner node to the graph
117 m[key] = g.Add(newV)
107c1cdb 118 log.Printf("[TRACE] MissingProviderTransformer: added implicit provisioner %s, first implied by %s", key, dag.VertexName(v))
bae9f6d2
JC
119 }
120 }
121
122 return nil
123}
124
125// CloseProvisionerTransformer is a GraphTransformer that adds nodes to the
126// graph that will close open provisioner connections that aren't needed
127// anymore. A provisioner connection is not needed anymore once all depended
128// resources in the graph are evaluated.
129type CloseProvisionerTransformer struct{}
130
131func (t *CloseProvisionerTransformer) Transform(g *Graph) error {
132 m := closeProvisionerVertexMap(g)
133 for _, v := range g.Vertices() {
134 if pv, ok := v.(GraphNodeProvisionerConsumer); ok {
135 for _, p := range pv.ProvisionedBy() {
136 source := m[p]
137
138 if source == nil {
139 // Create a new graphNodeCloseProvisioner and add it to the graph
140 source = &graphNodeCloseProvisioner{ProvisionerNameValue: p}
141 g.Add(source)
142
143 // Make sure we also add the new graphNodeCloseProvisioner to the map
144 // so we don't create and add any duplicate graphNodeCloseProvisioners.
145 m[p] = source
146 }
147
148 g.Connect(dag.BasicEdge(source, v))
149 }
150 }
151 }
152
153 return nil
154}
155
156// provisionerMapKey is a helper that gives us the key to use for the
157// maps returned by things such as provisionerVertexMap.
158func provisionerMapKey(k string, v dag.Vertex) string {
159 pathPrefix := ""
160 if sp, ok := v.(GraphNodeSubPath); ok {
107c1cdb 161 pathPrefix = sp.Path().String() + "."
bae9f6d2
JC
162 }
163
164 return pathPrefix + k
165}
166
167func provisionerVertexMap(g *Graph) map[string]dag.Vertex {
168 m := make(map[string]dag.Vertex)
169 for _, v := range g.Vertices() {
170 if pv, ok := v.(GraphNodeProvisioner); ok {
171 key := provisionerMapKey(pv.ProvisionerName(), v)
172 m[key] = v
173 }
174 }
175
176 return m
177}
178
179func closeProvisionerVertexMap(g *Graph) map[string]dag.Vertex {
180 m := make(map[string]dag.Vertex)
181 for _, v := range g.Vertices() {
182 if pv, ok := v.(GraphNodeCloseProvisioner); ok {
183 m[pv.CloseProvisionerName()] = v
184 }
185 }
186
187 return m
188}
189
190type graphNodeCloseProvisioner struct {
191 ProvisionerNameValue string
192}
193
194func (n *graphNodeCloseProvisioner) Name() string {
195 return fmt.Sprintf("provisioner.%s (close)", n.ProvisionerNameValue)
196}
197
198// GraphNodeEvalable impl.
199func (n *graphNodeCloseProvisioner) EvalTree() EvalNode {
200 return &EvalCloseProvisioner{Name: n.ProvisionerNameValue}
201}
202
203func (n *graphNodeCloseProvisioner) CloseProvisionerName() string {
204 return n.ProvisionerNameValue
205}