github.com/nicgrayson/terraform@v0.4.3-0.20150415203910-c4de50829380/terraform/graph_builder.go (about) 1 package terraform 2 3 import ( 4 "log" 5 6 "github.com/hashicorp/terraform/config/module" 7 ) 8 9 // GraphBuilder is an interface that can be implemented and used with 10 // Terraform to build the graph that Terraform walks. 11 type GraphBuilder interface { 12 // Build builds the graph for the given module path. It is up to 13 // the interface implementation whether this build should expand 14 // the graph or not. 15 Build(path []string) (*Graph, error) 16 } 17 18 // BasicGraphBuilder is a GraphBuilder that builds a graph out of a 19 // series of transforms and validates the graph is a valid structure. 20 type BasicGraphBuilder struct { 21 Steps []GraphTransformer 22 } 23 24 func (b *BasicGraphBuilder) Build(path []string) (*Graph, error) { 25 g := &Graph{Path: path} 26 for _, step := range b.Steps { 27 if err := step.Transform(g); err != nil { 28 return g, err 29 } 30 31 log.Printf( 32 "[TRACE] Graph after step %T:\n\n%s", 33 step, g.String()) 34 } 35 36 // Validate the graph structure 37 if err := g.Validate(); err != nil { 38 log.Printf("[ERROR] Graph validation failed. Graph:\n\n%s", g.String()) 39 return nil, err 40 } 41 42 return g, nil 43 } 44 45 // BuiltinGraphBuilder is responsible for building the complete graph that 46 // Terraform uses for execution. It is an opinionated builder that defines 47 // the step order required to build a complete graph as is used and expected 48 // by Terraform. 49 // 50 // If you require a custom graph, you'll have to build it up manually 51 // on your own by building a new GraphBuilder implementation. 52 type BuiltinGraphBuilder struct { 53 // Root is the root module of the graph to build. 54 Root *module.Tree 55 56 // Diff is the diff. The proper module diffs will be looked up. 57 Diff *Diff 58 59 // State is the global state. The proper module states will be looked 60 // up by graph path. 61 State *State 62 63 // Providers is the list of providers supported. 64 Providers []string 65 66 // Provisioners is the list of provisioners supported. 67 Provisioners []string 68 69 // Targets is the user-specified list of resources to target. 70 Targets []string 71 72 // Destroy is set to true when we're in a `terraform destroy` or a 73 // `terraform plan -destroy` 74 Destroy bool 75 } 76 77 // Build builds the graph according to the steps returned by Steps. 78 func (b *BuiltinGraphBuilder) Build(path []string) (*Graph, error) { 79 basic := &BasicGraphBuilder{ 80 Steps: b.Steps(), 81 } 82 83 return basic.Build(path) 84 } 85 86 // Steps returns the ordered list of GraphTransformers that must be executed 87 // to build a complete graph. 88 func (b *BuiltinGraphBuilder) Steps() []GraphTransformer { 89 return []GraphTransformer{ 90 // Create all our resources from the configuration and state 91 &ConfigTransformer{Module: b.Root}, 92 &OrphanTransformer{ 93 State: b.State, 94 Module: b.Root, 95 Targeting: (len(b.Targets) > 0), 96 }, 97 98 // Provider-related transformations 99 &MissingProviderTransformer{Providers: b.Providers}, 100 &ProviderTransformer{}, 101 &PruneProviderTransformer{}, 102 &DisableProviderTransformer{}, 103 104 // Provisioner-related transformations 105 &MissingProvisionerTransformer{Provisioners: b.Provisioners}, 106 &ProvisionerTransformer{}, 107 &PruneProvisionerTransformer{}, 108 109 // Run our vertex-level transforms 110 &VertexTransformer{ 111 Transforms: []GraphVertexTransformer{ 112 // Expand any statically expanded nodes, such as module graphs 113 &ExpandTransform{ 114 Builder: b, 115 }, 116 }, 117 }, 118 119 // Optionally reduces the graph to a user-specified list of targets and 120 // their dependencies. 121 &TargetsTransformer{Targets: b.Targets, Destroy: b.Destroy}, 122 123 // Create the destruction nodes 124 &DestroyTransformer{}, 125 &CreateBeforeDestroyTransformer{}, 126 &PruneDestroyTransformer{Diff: b.Diff, State: b.State}, 127 128 // Make sure we create one root 129 &RootTransformer{}, 130 131 // Perform the transitive reduction to make our graph a bit 132 // more sane if possible (it usually is possible). 133 &TransitiveReductionTransformer{}, 134 } 135 }