github.com/trawler/terraform@v0.10.8-0.20171106022149-4b1c7a1d9b48/terraform/transform_provider.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 8 "github.com/hashicorp/go-multierror" 9 "github.com/hashicorp/terraform/config/module" 10 "github.com/hashicorp/terraform/dag" 11 ) 12 13 // TODO: return the transformers and append them to the list, so we don't lose the log steps 14 func TransformProviders(providers []string, concrete ConcreteProviderNodeFunc, mod *module.Tree) GraphTransformer { 15 return GraphTransformMulti( 16 // Add providers from the config 17 &ProviderConfigTransformer{ 18 Module: mod, 19 Providers: providers, 20 Concrete: concrete, 21 }, 22 // Add any remaining missing providers 23 &MissingProviderTransformer{ 24 Providers: providers, 25 Concrete: concrete, 26 }, 27 // Connect the providers 28 &ProviderTransformer{}, 29 // Disable unused providers 30 &DisableProviderTransformer{}, 31 // Connect provider to their parent provider nodes 32 &ParentProviderTransformer{}, 33 // Attach configuration to each provider instance 34 &AttachProviderConfigTransformer{ 35 Module: mod, 36 }, 37 ) 38 } 39 40 // GraphNodeProvider is an interface that nodes that can be a provider 41 // must implement. 42 // ProviderName returns the name of the provider this satisfies. 43 // Name returns the full name of the provider in the config. 44 type GraphNodeProvider interface { 45 ProviderName() string 46 Name() string 47 } 48 49 // GraphNodeCloseProvider is an interface that nodes that can be a close 50 // provider must implement. The CloseProviderName returned is the name of 51 // the provider they satisfy. 52 type GraphNodeCloseProvider interface { 53 CloseProviderName() string 54 } 55 56 // GraphNodeProviderConsumer is an interface that nodes that require 57 // a provider must implement. ProvidedBy must return the name of the provider 58 // to use. 59 type GraphNodeProviderConsumer interface { 60 // TODO: make this return s string instead of a []string 61 ProvidedBy() []string 62 // Set the resolved provider address for this resource. 63 SetProvider(string) 64 } 65 66 // ProviderTransformer is a GraphTransformer that maps resources to 67 // providers within the graph. This will error if there are any resources 68 // that don't map to proper resources. 69 type ProviderTransformer struct{} 70 71 func (t *ProviderTransformer) Transform(g *Graph) error { 72 // Go through the other nodes and match them to providers they need 73 var err error 74 m := providerVertexMap(g) 75 for _, v := range g.Vertices() { 76 if pv, ok := v.(GraphNodeProviderConsumer); ok { 77 p := pv.ProvidedBy()[0] 78 79 key := providerMapKey(p, pv) 80 target := m[key] 81 82 sp, ok := pv.(GraphNodeSubPath) 83 if !ok && target == nil { 84 // no target, and no path to walk up 85 err = multierror.Append(err, fmt.Errorf( 86 "%s: provider %s couldn't be found", 87 dag.VertexName(v), p)) 88 break 89 } 90 91 // if we don't have a provider at this level, walk up the path looking for one 92 for i := 1; target == nil; i++ { 93 path := normalizeModulePath(sp.Path()) 94 if len(path) < i { 95 break 96 } 97 98 key = ResolveProviderName(p, path[:len(path)-i]) 99 target = m[key] 100 if target != nil { 101 break 102 } 103 } 104 105 if target == nil { 106 err = multierror.Append(err, fmt.Errorf( 107 "%s: provider %s couldn't be found", 108 dag.VertexName(v), p)) 109 break 110 } 111 112 pv.SetProvider(key) 113 g.Connect(dag.BasicEdge(v, target)) 114 } 115 } 116 117 return err 118 } 119 120 // CloseProviderTransformer is a GraphTransformer that adds nodes to the 121 // graph that will close open provider connections that aren't needed anymore. 122 // A provider connection is not needed anymore once all depended resources 123 // in the graph are evaluated. 124 type CloseProviderTransformer struct{} 125 126 // FIXME: this doesn't close providers if the root provider is disabled 127 func (t *CloseProviderTransformer) Transform(g *Graph) error { 128 pm := providerVertexMap(g) 129 cpm := make(map[string]*graphNodeCloseProvider) 130 var err error 131 132 for _, v := range pm { 133 p := v.(GraphNodeProvider) 134 135 // get the close provider of this type if we alread created it 136 closer := cpm[p.ProviderName()] 137 138 if closer == nil { 139 // create a closer for this provider type 140 closer = &graphNodeCloseProvider{ProviderNameValue: p.ProviderName()} 141 g.Add(closer) 142 cpm[p.ProviderName()] = closer 143 } 144 145 // Close node depends on the provider itself 146 // this is added unconditionally, so it will connect to all instances 147 // of the provider. Extra edges will be removed by transitive 148 // reduction. 149 g.Connect(dag.BasicEdge(closer, p)) 150 151 // connect all the provider's resources to the close node 152 for _, s := range g.UpEdges(p).List() { 153 if _, ok := s.(GraphNodeProviderConsumer); ok { 154 g.Connect(dag.BasicEdge(closer, s)) 155 } 156 } 157 } 158 159 return err 160 } 161 162 // MissingProviderTransformer is a GraphTransformer that adds nodes for all 163 // required providers into the graph. Specifically, it creates provider 164 // configuration nodes for all the providers that we support. These are pruned 165 // later during an optimization pass. 166 type MissingProviderTransformer struct { 167 // Providers is the list of providers we support. 168 Providers []string 169 170 // Concrete, if set, overrides how the providers are made. 171 Concrete ConcreteProviderNodeFunc 172 } 173 174 func (t *MissingProviderTransformer) Transform(g *Graph) error { 175 // Initialize factory 176 if t.Concrete == nil { 177 t.Concrete = func(a *NodeAbstractProvider) dag.Vertex { 178 return a 179 } 180 } 181 182 var err error 183 m := providerVertexMap(g) 184 for _, v := range g.Vertices() { 185 pv, ok := v.(GraphNodeProviderConsumer) 186 if !ok { 187 continue 188 } 189 190 p := pv.ProvidedBy()[0] 191 key := ResolveProviderName(p, nil) 192 provider := m[key] 193 194 // we already have it 195 if provider != nil { 196 continue 197 } 198 199 // create the misisng top-level provider 200 provider = t.Concrete(&NodeAbstractProvider{ 201 NameValue: p, 202 }).(dag.Vertex) 203 204 m[key] = g.Add(provider) 205 } 206 207 return err 208 } 209 210 // ParentProviderTransformer connects provider nodes to their parents. 211 // 212 // This works by finding nodes that are both GraphNodeProviders and 213 // GraphNodeSubPath. It then connects the providers to their parent 214 // path. The parent provider is always at the root level. 215 type ParentProviderTransformer struct{} 216 217 func (t *ParentProviderTransformer) Transform(g *Graph) error { 218 pm := providerVertexMap(g) 219 for _, v := range g.Vertices() { 220 // Only care about providers 221 pn, ok := v.(GraphNodeProvider) 222 if !ok || pn.ProviderName() == "" { 223 continue 224 } 225 226 // Also require a subpath, if there is no subpath then we 227 // can't have a parent. 228 if pn, ok := v.(GraphNodeSubPath); ok { 229 if len(normalizeModulePath(pn.Path())) <= 1 { 230 continue 231 } 232 } 233 234 // this provider may be disabled, but we can only get it's name from 235 // the ProviderName string 236 name := ResolveProviderName(strings.SplitN(pn.ProviderName(), " ", 2)[0], nil) 237 parent := pm[name] 238 if parent != nil { 239 g.Connect(dag.BasicEdge(v, parent)) 240 } 241 242 } 243 return nil 244 } 245 246 // PruneProviderTransformer is a GraphTransformer that prunes all the 247 // providers that aren't needed from the graph. A provider is unneeded if 248 // no resource or module is using that provider. 249 type PruneProviderTransformer struct{} 250 251 func (t *PruneProviderTransformer) Transform(g *Graph) error { 252 for _, v := range g.Vertices() { 253 // We only care about the providers 254 if pn, ok := v.(GraphNodeProvider); !ok || pn.ProviderName() == "" { 255 continue 256 } 257 // Does anything depend on this? If not, then prune it. 258 if s := g.UpEdges(v); s.Len() == 0 { 259 if nv, ok := v.(dag.NamedVertex); ok { 260 log.Printf("[DEBUG] Pruning provider with no dependencies: %s", nv.Name()) 261 } 262 g.Remove(v) 263 } 264 } 265 266 return nil 267 } 268 269 // providerMapKey is a helper that gives us the key to use for the 270 // maps returned by things such as providerVertexMap. 271 func providerMapKey(k string, v dag.Vertex) string { 272 // we create a dummy provider to 273 var path []string 274 if sp, ok := v.(GraphNodeSubPath); ok { 275 path = normalizeModulePath(sp.Path()) 276 } 277 return ResolveProviderName(k, path) 278 } 279 280 func providerVertexMap(g *Graph) map[string]dag.Vertex { 281 m := make(map[string]dag.Vertex) 282 for _, v := range g.Vertices() { 283 if pv, ok := v.(GraphNodeProvider); ok { 284 // TODO: The Name may have meta info, like " (disabled)" 285 name := strings.SplitN(pv.Name(), " ", 2)[0] 286 m[name] = v 287 } 288 } 289 290 return m 291 } 292 293 func closeProviderVertexMap(g *Graph) map[string]dag.Vertex { 294 m := make(map[string]dag.Vertex) 295 for _, v := range g.Vertices() { 296 if pv, ok := v.(GraphNodeCloseProvider); ok { 297 m[pv.CloseProviderName()] = v 298 } 299 } 300 301 return m 302 } 303 304 type graphNodeCloseProvider struct { 305 ProviderNameValue string 306 } 307 308 func (n *graphNodeCloseProvider) Name() string { 309 return fmt.Sprintf("provider.%s (close)", n.ProviderNameValue) 310 } 311 312 // GraphNodeEvalable impl. 313 func (n *graphNodeCloseProvider) EvalTree() EvalNode { 314 return CloseProviderEvalTree(n.ProviderNameValue) 315 } 316 317 // GraphNodeDependable impl. 318 func (n *graphNodeCloseProvider) DependableName() []string { 319 return []string{n.Name()} 320 } 321 322 func (n *graphNodeCloseProvider) CloseProviderName() string { 323 return n.ProviderNameValue 324 } 325 326 // GraphNodeDotter impl. 327 func (n *graphNodeCloseProvider) DotNode(name string, opts *dag.DotOpts) *dag.DotNode { 328 if !opts.Verbose { 329 return nil 330 } 331 return &dag.DotNode{ 332 Name: name, 333 Attrs: map[string]string{ 334 "label": n.Name(), 335 "shape": "diamond", 336 }, 337 } 338 } 339 340 // RemovableIfNotTargeted 341 func (n *graphNodeCloseProvider) RemoveIfNotTargeted() bool { 342 // We need to add this so that this node will be removed if 343 // it isn't targeted or a dependency of a target. 344 return true 345 } 346 347 // graphNodeProviderConsumerDummy is a struct that never enters the real 348 // graph (though it could to no ill effect). It implements 349 // GraphNodeProviderConsumer and GraphNodeSubpath as a way to force 350 // certain transformations. 351 type graphNodeProviderConsumerDummy struct { 352 ProviderValue string 353 PathValue []string 354 } 355 356 func (n *graphNodeProviderConsumerDummy) Path() []string { 357 return n.PathValue 358 } 359 360 func (n *graphNodeProviderConsumerDummy) ProvidedBy() []string { 361 return []string{n.ProviderValue} 362 } 363 364 func (n *graphNodeProviderConsumerDummy) SetProvider(string) {}