github.com/hobbeswalsh/terraform@v0.3.7-0.20150619183303-ad17cf55a0fa/terraform/transform_provider.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 6 "github.com/hashicorp/go-multierror" 7 "github.com/hashicorp/terraform/config" 8 "github.com/hashicorp/terraform/dag" 9 "github.com/hashicorp/terraform/dot" 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 ProviderConfig() *config.RawConfig 18 } 19 20 // GraphNodeProviderConsumer is an interface that nodes that require 21 // a provider must implement. ProvidedBy must return the name of the provider 22 // to use. 23 type GraphNodeProviderConsumer interface { 24 ProvidedBy() []string 25 } 26 27 // DisableProviderTransformer "disables" any providers that are only 28 // depended on by modules. 29 type DisableProviderTransformer struct{} 30 31 func (t *DisableProviderTransformer) Transform(g *Graph) error { 32 for _, v := range g.Vertices() { 33 // We only care about providers 34 pn, ok := v.(GraphNodeProvider) 35 if !ok || pn.ProviderName() == "" { 36 continue 37 } 38 39 // Go through all the up-edges (things that depend on this 40 // provider) and if any is not a module, then ignore this node. 41 nonModule := false 42 for _, sourceRaw := range g.UpEdges(v).List() { 43 source := sourceRaw.(dag.Vertex) 44 cn, ok := source.(graphNodeConfig) 45 if !ok { 46 nonModule = true 47 break 48 } 49 50 if cn.ConfigType() != GraphNodeConfigTypeModule { 51 nonModule = true 52 break 53 } 54 } 55 if nonModule { 56 // We found something that depends on this provider that 57 // isn't a module, so skip it. 58 continue 59 } 60 61 // Disable the provider by replacing it with a "disabled" provider 62 disabled := &graphNodeDisabledProvider{GraphNodeProvider: pn} 63 if !g.Replace(v, disabled) { 64 panic(fmt.Sprintf( 65 "vertex disappeared from under us: %s", 66 dag.VertexName(v))) 67 } 68 } 69 70 return nil 71 } 72 73 // ProviderTransformer is a GraphTransformer that maps resources to 74 // providers within the graph. This will error if there are any resources 75 // that don't map to proper resources. 76 type ProviderTransformer struct{} 77 78 func (t *ProviderTransformer) Transform(g *Graph) error { 79 // Go through the other nodes and match them to providers they need 80 var err error 81 m := providerVertexMap(g) 82 for _, v := range g.Vertices() { 83 if pv, ok := v.(GraphNodeProviderConsumer); ok { 84 for _, p := range pv.ProvidedBy() { 85 target := m[p] 86 if target == nil { 87 err = multierror.Append(err, fmt.Errorf( 88 "%s: provider %s couldn't be found", 89 dag.VertexName(v), p)) 90 continue 91 } 92 93 g.Connect(dag.BasicEdge(v, target)) 94 } 95 } 96 } 97 98 return err 99 } 100 101 // MissingProviderTransformer is a GraphTransformer that adds nodes 102 // for missing providers into the graph. Specifically, it creates provider 103 // configuration nodes for all the providers that we support. These are 104 // pruned later during an optimization pass. 105 type MissingProviderTransformer struct { 106 // Providers is the list of providers we support. 107 Providers []string 108 } 109 110 func (t *MissingProviderTransformer) Transform(g *Graph) error { 111 m := providerVertexMap(g) 112 for _, p := range t.Providers { 113 if _, ok := m[p]; ok { 114 // This provider already exists as a configured node 115 continue 116 } 117 118 // Add our own missing provider node to the graph 119 g.Add(&graphNodeMissingProvider{ProviderNameValue: p}) 120 } 121 122 return nil 123 } 124 125 // PruneProviderTransformer is a GraphTransformer that prunes all the 126 // providers that aren't needed from the graph. A provider is unneeded if 127 // no resource or module is using that provider. 128 type PruneProviderTransformer struct{} 129 130 func (t *PruneProviderTransformer) Transform(g *Graph) error { 131 for _, v := range g.Vertices() { 132 // We only care about the providers 133 if pn, ok := v.(GraphNodeProvider); !ok || pn.ProviderName() == "" { 134 continue 135 } 136 137 // Does anything depend on this? If not, then prune it. 138 if s := g.UpEdges(v); s.Len() == 0 { 139 g.Remove(v) 140 } 141 } 142 143 return nil 144 } 145 146 type graphNodeDisabledProvider struct { 147 GraphNodeProvider 148 } 149 150 // GraphNodeEvalable impl. 151 func (n *graphNodeDisabledProvider) EvalTree() EvalNode { 152 var resourceConfig *ResourceConfig 153 154 return &EvalOpFilter{ 155 Ops: []walkOperation{walkInput, walkValidate, walkRefresh, walkPlan, walkApply}, 156 Node: &EvalSequence{ 157 Nodes: []EvalNode{ 158 &EvalInterpolate{ 159 Config: n.ProviderConfig(), 160 Output: &resourceConfig, 161 }, 162 &EvalBuildProviderConfig{ 163 Provider: n.ProviderName(), 164 Config: &resourceConfig, 165 Output: &resourceConfig, 166 }, 167 &EvalSetProviderConfig{ 168 Provider: n.ProviderName(), 169 Config: &resourceConfig, 170 }, 171 }, 172 }, 173 } 174 } 175 176 // GraphNodeFlattenable impl. 177 func (n *graphNodeDisabledProvider) Flatten(p []string) (dag.Vertex, error) { 178 return &graphNodeDisabledProviderFlat{ 179 graphNodeDisabledProvider: n, 180 PathValue: p, 181 }, nil 182 } 183 184 func (n *graphNodeDisabledProvider) Name() string { 185 return fmt.Sprintf("%s (disabled)", dag.VertexName(n.GraphNodeProvider)) 186 } 187 188 // GraphNodeDotter impl. 189 func (n *graphNodeDisabledProvider) DotNode(name string, opts *GraphDotOpts) *dot.Node { 190 return dot.NewNode(name, map[string]string{ 191 "label": n.Name(), 192 "shape": "diamond", 193 }) 194 } 195 196 // GraphNodeDotterOrigin impl. 197 func (n *graphNodeDisabledProvider) DotOrigin() bool { 198 return true 199 } 200 201 // GraphNodeDependable impl. 202 func (n *graphNodeDisabledProvider) DependableName() []string { 203 return []string{"provider." + n.ProviderName()} 204 } 205 206 // GraphNodeProvider impl. 207 func (n *graphNodeDisabledProvider) ProviderName() string { 208 return n.GraphNodeProvider.ProviderName() 209 } 210 211 // GraphNodeProvider impl. 212 func (n *graphNodeDisabledProvider) ProviderConfig() *config.RawConfig { 213 return n.GraphNodeProvider.ProviderConfig() 214 } 215 216 // Same as graphNodeDisabledProvider, but for flattening 217 type graphNodeDisabledProviderFlat struct { 218 *graphNodeDisabledProvider 219 220 PathValue []string 221 } 222 223 func (n *graphNodeDisabledProviderFlat) Name() string { 224 return fmt.Sprintf( 225 "%s.%s", modulePrefixStr(n.PathValue), n.graphNodeDisabledProvider.Name()) 226 } 227 228 func (n *graphNodeDisabledProviderFlat) Path() []string { 229 return n.PathValue 230 } 231 232 func (n *graphNodeDisabledProviderFlat) ProviderName() string { 233 return fmt.Sprintf( 234 "%s.%s", modulePrefixStr(n.PathValue), 235 n.graphNodeDisabledProvider.ProviderName()) 236 } 237 238 // GraphNodeDependable impl. 239 func (n *graphNodeDisabledProviderFlat) DependableName() []string { 240 return []string{n.Name()} 241 } 242 243 func (n *graphNodeDisabledProviderFlat) DependentOn() []string { 244 var result []string 245 246 // If we're in a module, then depend on our parent's provider 247 if len(n.PathValue) > 1 { 248 prefix := modulePrefixStr(n.PathValue[:len(n.PathValue)-1]) 249 if prefix != "" { 250 prefix += "." 251 } 252 253 result = append(result, fmt.Sprintf( 254 "%s%s", 255 prefix, n.graphNodeDisabledProvider.Name())) 256 } 257 258 return result 259 } 260 261 type graphNodeMissingProvider struct { 262 ProviderNameValue string 263 } 264 265 func (n *graphNodeMissingProvider) Name() string { 266 return fmt.Sprintf("provider.%s", n.ProviderNameValue) 267 } 268 269 // GraphNodeEvalable impl. 270 func (n *graphNodeMissingProvider) EvalTree() EvalNode { 271 return ProviderEvalTree(n.ProviderNameValue, nil) 272 } 273 274 // GraphNodeDependable impl. 275 func (n *graphNodeMissingProvider) DependableName() []string { 276 return []string{n.Name()} 277 } 278 279 func (n *graphNodeMissingProvider) ProviderName() string { 280 return n.ProviderNameValue 281 } 282 283 func (n *graphNodeMissingProvider) ProviderConfig() *config.RawConfig { 284 return nil 285 } 286 287 // GraphNodeDotter impl. 288 func (n *graphNodeMissingProvider) DotNode(name string, opts *GraphDotOpts) *dot.Node { 289 return dot.NewNode(name, map[string]string{ 290 "label": n.Name(), 291 "shape": "diamond", 292 }) 293 } 294 295 // GraphNodeDotterOrigin impl. 296 func (n *graphNodeMissingProvider) DotOrigin() bool { 297 return true 298 } 299 300 // GraphNodeFlattenable impl. 301 func (n *graphNodeMissingProvider) Flatten(p []string) (dag.Vertex, error) { 302 return &graphNodeMissingProviderFlat{ 303 graphNodeMissingProvider: n, 304 PathValue: p, 305 }, nil 306 } 307 308 func providerVertexMap(g *Graph) map[string]dag.Vertex { 309 m := make(map[string]dag.Vertex) 310 for _, v := range g.Vertices() { 311 if pv, ok := v.(GraphNodeProvider); ok { 312 m[pv.ProviderName()] = v 313 } 314 } 315 316 return m 317 } 318 319 // Same as graphNodeMissingProvider, but for flattening 320 type graphNodeMissingProviderFlat struct { 321 *graphNodeMissingProvider 322 323 PathValue []string 324 } 325 326 func (n *graphNodeMissingProviderFlat) Name() string { 327 return fmt.Sprintf( 328 "%s.%s", modulePrefixStr(n.PathValue), n.graphNodeMissingProvider.Name()) 329 } 330 331 func (n *graphNodeMissingProviderFlat) Path() []string { 332 return n.PathValue 333 } 334 335 func (n *graphNodeMissingProviderFlat) ProviderName() string { 336 return fmt.Sprintf( 337 "%s.%s", modulePrefixStr(n.PathValue), 338 n.graphNodeMissingProvider.ProviderName()) 339 } 340 341 // GraphNodeDependable impl. 342 func (n *graphNodeMissingProviderFlat) DependableName() []string { 343 return []string{n.Name()} 344 } 345 346 func (n *graphNodeMissingProviderFlat) DependentOn() []string { 347 var result []string 348 349 // If we're in a module, then depend on our parent's provider 350 if len(n.PathValue) > 1 { 351 prefix := modulePrefixStr(n.PathValue[:len(n.PathValue)-1]) 352 if prefix != "" { 353 prefix += "." 354 } 355 356 result = append(result, fmt.Sprintf( 357 "%s%s", 358 prefix, n.graphNodeMissingProvider.Name())) 359 } 360 361 return result 362 }