github.com/tarrant/terraform@v0.3.8-0.20150402012457-f68c9eee638e/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/dag" 8 ) 9 10 // GraphNodeProvider is an interface that nodes that can be a provider 11 // must implement. The ProviderName returned is the name of the provider 12 // they satisfy. 13 type GraphNodeProvider interface { 14 ProviderName() string 15 } 16 17 // GraphNodeProviderConsumer is an interface that nodes that require 18 // a provider must implement. ProvidedBy must return the name of the provider 19 // to use. 20 type GraphNodeProviderConsumer interface { 21 ProvidedBy() []string 22 } 23 24 // ProviderTransformer is a GraphTransformer that maps resources to 25 // providers within the graph. This will error if there are any resources 26 // that don't map to proper resources. 27 type ProviderTransformer struct{} 28 29 func (t *ProviderTransformer) Transform(g *Graph) error { 30 // Go through the other nodes and match them to providers they need 31 var err error 32 m := providerVertexMap(g) 33 for _, v := range g.Vertices() { 34 if pv, ok := v.(GraphNodeProviderConsumer); ok { 35 for _, p := range pv.ProvidedBy() { 36 target := m[p] 37 if target == nil { 38 err = multierror.Append(err, fmt.Errorf( 39 "%s: provider %s couldn't be found", 40 dag.VertexName(v), p)) 41 continue 42 } 43 44 g.Connect(dag.BasicEdge(v, target)) 45 } 46 } 47 } 48 49 return err 50 } 51 52 // MissingProviderTransformer is a GraphTransformer that adds nodes 53 // for missing providers into the graph. Specifically, it creates provider 54 // configuration nodes for all the providers that we support. These are 55 // pruned later during an optimization pass. 56 type MissingProviderTransformer struct { 57 // Providers is the list of providers we support. 58 Providers []string 59 } 60 61 func (t *MissingProviderTransformer) Transform(g *Graph) error { 62 m := providerVertexMap(g) 63 for _, p := range t.Providers { 64 if _, ok := m[p]; ok { 65 // This provider already exists as a configured node 66 continue 67 } 68 69 // Add our own missing provider node to the graph 70 g.Add(&graphNodeMissingProvider{ProviderNameValue: p}) 71 } 72 73 return nil 74 } 75 76 // PruneProviderTransformer is a GraphTransformer that prunes all the 77 // providers that aren't needed from the graph. A provider is unneeded if 78 // no resource or module is using that provider. 79 type PruneProviderTransformer struct{} 80 81 func (t *PruneProviderTransformer) Transform(g *Graph) error { 82 for _, v := range g.Vertices() { 83 // We only care about the providers 84 if _, ok := v.(GraphNodeProvider); !ok { 85 continue 86 } 87 88 // Does anything depend on this? If not, then prune it. 89 if s := g.UpEdges(v); s.Len() == 0 { 90 g.Remove(v) 91 } 92 } 93 94 return nil 95 } 96 97 type graphNodeMissingProvider struct { 98 ProviderNameValue string 99 } 100 101 func (n *graphNodeMissingProvider) Name() string { 102 return fmt.Sprintf("provider.%s", n.ProviderNameValue) 103 } 104 105 // GraphNodeEvalable impl. 106 func (n *graphNodeMissingProvider) EvalTree() EvalNode { 107 return ProviderEvalTree(n.ProviderNameValue, nil) 108 } 109 110 func (n *graphNodeMissingProvider) ProviderName() string { 111 return n.ProviderNameValue 112 } 113 114 // GraphNodeDotter impl. 115 func (n *graphNodeMissingProvider) Dot(name string) string { 116 return fmt.Sprintf( 117 "\"%s\" [\n"+ 118 "\tlabel=\"%s\"\n"+ 119 "\tshape=diamond\n"+ 120 "];", 121 name, 122 n.Name()) 123 } 124 125 func providerVertexMap(g *Graph) map[string]dag.Vertex { 126 m := make(map[string]dag.Vertex) 127 for _, v := range g.Vertices() { 128 if pv, ok := v.(GraphNodeProvider); ok { 129 m[pv.ProviderName()] = v 130 } 131 } 132 133 return m 134 }