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