github.com/jgadling/terraform@v0.3.8-0.20150227214559-abd68c2c87bc/terraform/transform_provisioner.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 // 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 // GraphNodeProvisionerConsumer is an interface that nodes that require 18 // a provisioner must implement. ProvisionedBy must return the name of the 19 // provisioner to use. 20 type GraphNodeProvisionerConsumer interface { 21 ProvisionedBy() []string 22 } 23 24 // ProvisionerTransformer is a GraphTransformer that maps resources to 25 // provisioners within the graph. This will error if there are any resources 26 // that don't map to proper resources. 27 type ProvisionerTransformer struct{} 28 29 func (t *ProvisionerTransformer) Transform(g *Graph) error { 30 // Go through the other nodes and match them to provisioners they need 31 var err error 32 m := provisionerVertexMap(g) 33 for _, v := range g.Vertices() { 34 if pv, ok := v.(GraphNodeProvisionerConsumer); ok { 35 for _, provisionerName := range pv.ProvisionedBy() { 36 target := m[provisionerName] 37 if target == nil { 38 err = multierror.Append(err, fmt.Errorf( 39 "%s: provisioner %s couldn't be found", 40 dag.VertexName(v), provisionerName)) 41 continue 42 } 43 44 g.Connect(dag.BasicEdge(v, target)) 45 } 46 } 47 } 48 49 return err 50 } 51 52 // MissingProvisionerTransformer is a GraphTransformer that adds nodes 53 // for missing provisioners into the graph. Specifically, it creates provisioner 54 // configuration nodes for all the provisioners that we support. These are 55 // pruned later during an optimization pass. 56 type MissingProvisionerTransformer struct { 57 // Provisioners is the list of provisioners we support. 58 Provisioners []string 59 } 60 61 func (t *MissingProvisionerTransformer) Transform(g *Graph) error { 62 m := provisionerVertexMap(g) 63 for _, p := range t.Provisioners { 64 if _, ok := m[p]; ok { 65 // This provisioner already exists as a configured node 66 continue 67 } 68 69 // Add our own missing provisioner node to the graph 70 g.Add(&graphNodeMissingProvisioner{ProvisionerNameValue: p}) 71 } 72 73 return nil 74 } 75 76 // PruneProvisionerTransformer is a GraphTransformer that prunes all the 77 // provisioners that aren't needed from the graph. A provisioner is unneeded if 78 // no resource or module is using that provisioner. 79 type PruneProvisionerTransformer struct{} 80 81 func (t *PruneProvisionerTransformer) Transform(g *Graph) error { 82 for _, v := range g.Vertices() { 83 // We only care about the provisioners 84 if _, ok := v.(GraphNodeProvisioner); !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 graphNodeMissingProvisioner struct { 98 ProvisionerNameValue string 99 } 100 101 func (n *graphNodeMissingProvisioner) Name() string { 102 return fmt.Sprintf("provisioner.%s", n.ProvisionerNameValue) 103 } 104 105 // GraphNodeEvalable impl. 106 func (n *graphNodeMissingProvisioner) EvalTree() EvalNode { 107 return &EvalInitProvisioner{Name: n.ProvisionerNameValue} 108 } 109 110 func (n *graphNodeMissingProvisioner) ProvisionerName() string { 111 return n.ProvisionerNameValue 112 } 113 114 func provisionerVertexMap(g *Graph) map[string]dag.Vertex { 115 m := make(map[string]dag.Vertex) 116 for _, v := range g.Vertices() { 117 if pv, ok := v.(GraphNodeProvisioner); ok { 118 m[pv.ProvisionerName()] = v 119 } 120 } 121 122 return m 123 }