github.com/nicgrayson/terraform@v0.4.3-0.20150415203910-c4de50829380/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 ) 10 11 // GraphNodeProvider is an interface that nodes that can be a provider 12 // must implement. The ProviderName returned is the name of the provider 13 // they satisfy. 14 type GraphNodeProvider interface { 15 ProviderName() string 16 ProviderConfig() *config.RawConfig 17 } 18 19 // GraphNodeProviderConsumer is an interface that nodes that require 20 // a provider must implement. ProvidedBy must return the name of the provider 21 // to use. 22 type GraphNodeProviderConsumer interface { 23 ProvidedBy() []string 24 } 25 26 // DisableProviderTransformer "disables" any providers that are only 27 // depended on by modules. 28 type DisableProviderTransformer struct{} 29 30 func (t *DisableProviderTransformer) Transform(g *Graph) error { 31 for _, v := range g.Vertices() { 32 // We only care about providers 33 pn, ok := v.(GraphNodeProvider) 34 if !ok { 35 continue 36 } 37 38 // Go through all the up-edges (things that depend on this 39 // provider) and if any is not a module, then ignore this node. 40 nonModule := false 41 for _, sourceRaw := range g.UpEdges(v).List() { 42 source := sourceRaw.(dag.Vertex) 43 cn, ok := source.(graphNodeConfig) 44 if !ok { 45 nonModule = true 46 break 47 } 48 49 if cn.ConfigType() != GraphNodeConfigTypeModule { 50 nonModule = true 51 break 52 } 53 } 54 if nonModule { 55 // We found something that depends on this provider that 56 // isn't a module, so skip it. 57 continue 58 } 59 60 // Disable the provider by replacing it with a "disabled" provider 61 disabled := &graphNodeDisabledProvider{GraphNodeProvider: pn} 62 if !g.Replace(v, disabled) { 63 panic(fmt.Sprintf( 64 "vertex disappeared from under us: %s", 65 dag.VertexName(v))) 66 } 67 } 68 69 return nil 70 } 71 72 // ProviderTransformer is a GraphTransformer that maps resources to 73 // providers within the graph. This will error if there are any resources 74 // that don't map to proper resources. 75 type ProviderTransformer struct{} 76 77 func (t *ProviderTransformer) Transform(g *Graph) error { 78 // Go through the other nodes and match them to providers they need 79 var err error 80 m := providerVertexMap(g) 81 for _, v := range g.Vertices() { 82 if pv, ok := v.(GraphNodeProviderConsumer); ok { 83 for _, p := range pv.ProvidedBy() { 84 target := m[p] 85 if target == nil { 86 err = multierror.Append(err, fmt.Errorf( 87 "%s: provider %s couldn't be found", 88 dag.VertexName(v), p)) 89 continue 90 } 91 92 g.Connect(dag.BasicEdge(v, target)) 93 } 94 } 95 } 96 97 return err 98 } 99 100 // MissingProviderTransformer is a GraphTransformer that adds nodes 101 // for missing providers into the graph. Specifically, it creates provider 102 // configuration nodes for all the providers that we support. These are 103 // pruned later during an optimization pass. 104 type MissingProviderTransformer struct { 105 // Providers is the list of providers we support. 106 Providers []string 107 } 108 109 func (t *MissingProviderTransformer) Transform(g *Graph) error { 110 m := providerVertexMap(g) 111 for _, p := range t.Providers { 112 if _, ok := m[p]; ok { 113 // This provider already exists as a configured node 114 continue 115 } 116 117 // Add our own missing provider node to the graph 118 g.Add(&graphNodeMissingProvider{ProviderNameValue: p}) 119 } 120 121 return nil 122 } 123 124 // PruneProviderTransformer is a GraphTransformer that prunes all the 125 // providers that aren't needed from the graph. A provider is unneeded if 126 // no resource or module is using that provider. 127 type PruneProviderTransformer struct{} 128 129 func (t *PruneProviderTransformer) Transform(g *Graph) error { 130 for _, v := range g.Vertices() { 131 // We only care about the providers 132 if _, ok := v.(GraphNodeProvider); !ok { 133 continue 134 } 135 136 // Does anything depend on this? If not, then prune it. 137 if s := g.UpEdges(v); s.Len() == 0 { 138 g.Remove(v) 139 } 140 } 141 142 return nil 143 } 144 145 type graphNodeDisabledProvider struct { 146 GraphNodeProvider 147 } 148 149 // GraphNodeEvalable impl. 150 func (n *graphNodeDisabledProvider) EvalTree() EvalNode { 151 var resourceConfig *ResourceConfig 152 153 return &EvalOpFilter{ 154 Ops: []walkOperation{walkInput, walkValidate, walkRefresh, walkPlan, walkApply}, 155 Node: &EvalSequence{ 156 Nodes: []EvalNode{ 157 &EvalInterpolate{ 158 Config: n.ProviderConfig(), 159 Output: &resourceConfig, 160 }, 161 &EvalBuildProviderConfig{ 162 Provider: n.ProviderName(), 163 Config: &resourceConfig, 164 Output: &resourceConfig, 165 }, 166 &EvalSetProviderConfig{ 167 Provider: n.ProviderName(), 168 Config: &resourceConfig, 169 }, 170 }, 171 }, 172 } 173 } 174 175 func (n *graphNodeDisabledProvider) Name() string { 176 return fmt.Sprintf("%s (disabled)", dag.VertexName(n.GraphNodeProvider)) 177 } 178 179 type graphNodeMissingProvider struct { 180 ProviderNameValue string 181 } 182 183 func (n *graphNodeMissingProvider) Name() string { 184 return fmt.Sprintf("provider.%s", n.ProviderNameValue) 185 } 186 187 // GraphNodeEvalable impl. 188 func (n *graphNodeMissingProvider) EvalTree() EvalNode { 189 return ProviderEvalTree(n.ProviderNameValue, nil) 190 } 191 192 func (n *graphNodeMissingProvider) ProviderName() string { 193 return n.ProviderNameValue 194 } 195 196 func (n *graphNodeMissingProvider) ProviderConfig() *config.RawConfig { 197 return nil 198 } 199 200 // GraphNodeDotter impl. 201 func (n *graphNodeMissingProvider) Dot(name string) string { 202 return fmt.Sprintf( 203 "\"%s\" [\n"+ 204 "\tlabel=\"%s\"\n"+ 205 "\tshape=diamond\n"+ 206 "];", 207 name, 208 n.Name()) 209 } 210 211 func providerVertexMap(g *Graph) map[string]dag.Vertex { 212 m := make(map[string]dag.Vertex) 213 for _, v := range g.Vertices() { 214 if pv, ok := v.(GraphNodeProvider); ok { 215 m[pv.ProviderName()] = v 216 } 217 } 218 219 return m 220 }