github.com/paulmey/terraform@v0.5.2-0.20150519145237-046e9b4c884d/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 // GraphNodeFlattenable impl. 115 func (n *graphNodeMissingProvisioner) Flatten(p []string) (dag.Vertex, error) { 116 return &graphNodeMissingProvisionerFlat{ 117 graphNodeMissingProvisioner: n, 118 PathValue: p, 119 }, nil 120 } 121 122 func provisionerVertexMap(g *Graph) map[string]dag.Vertex { 123 m := make(map[string]dag.Vertex) 124 for _, v := range g.Vertices() { 125 if pv, ok := v.(GraphNodeProvisioner); ok { 126 m[pv.ProvisionerName()] = v 127 } 128 } 129 130 return m 131 } 132 133 // Same as graphNodeMissingProvisioner, but for flattening 134 type graphNodeMissingProvisionerFlat struct { 135 *graphNodeMissingProvisioner 136 137 PathValue []string 138 } 139 140 func (n *graphNodeMissingProvisionerFlat) Name() string { 141 return fmt.Sprintf( 142 "%s.%s", modulePrefixStr(n.PathValue), n.graphNodeMissingProvisioner.Name()) 143 } 144 145 func (n *graphNodeMissingProvisionerFlat) Path() []string { 146 return n.PathValue 147 } 148 149 func (n *graphNodeMissingProvisionerFlat) ProvisionerName() string { 150 return fmt.Sprintf( 151 "%s.%s", modulePrefixStr(n.PathValue), 152 n.graphNodeMissingProvisioner.ProvisionerName()) 153 }