github.com/posener/terraform@v0.11.0-beta1.0.20171103235147-645df36af025/terraform/graph_builder_plan.go (about) 1 package terraform 2 3 import ( 4 "sync" 5 6 "github.com/hashicorp/terraform/config/module" 7 "github.com/hashicorp/terraform/dag" 8 ) 9 10 // PlanGraphBuilder implements GraphBuilder and is responsible for building 11 // a graph for planning (creating a Terraform Diff). 12 // 13 // The primary difference between this graph and others: 14 // 15 // * Based on the config since it represents the target state 16 // 17 // * Ignores lifecycle options since no lifecycle events occur here. This 18 // simplifies the graph significantly since complex transforms such as 19 // create-before-destroy can be completely ignored. 20 // 21 type PlanGraphBuilder struct { 22 // Module is the root module for the graph to build. 23 Module *module.Tree 24 25 // State is the current state 26 State *State 27 28 // Providers is the list of providers supported. 29 Providers []string 30 31 // Provisioners is the list of provisioners supported. 32 Provisioners []string 33 34 // Targets are resources to target 35 Targets []string 36 37 // DisableReduce, if true, will not reduce the graph. Great for testing. 38 DisableReduce bool 39 40 // Validate will do structural validation of the graph. 41 Validate bool 42 43 // CustomConcrete can be set to customize the node types created 44 // for various parts of the plan. This is useful in order to customize 45 // the plan behavior. 46 CustomConcrete bool 47 ConcreteProvider ConcreteProviderNodeFunc 48 ConcreteResource ConcreteResourceNodeFunc 49 ConcreteResourceOrphan ConcreteResourceNodeFunc 50 51 once sync.Once 52 } 53 54 // See GraphBuilder 55 func (b *PlanGraphBuilder) Build(path []string) (*Graph, error) { 56 return (&BasicGraphBuilder{ 57 Steps: b.Steps(), 58 Validate: b.Validate, 59 Name: "PlanGraphBuilder", 60 }).Build(path) 61 } 62 63 // See GraphBuilder 64 func (b *PlanGraphBuilder) Steps() []GraphTransformer { 65 b.once.Do(b.init) 66 67 steps := []GraphTransformer{ 68 // Creates all the resources represented in the config 69 &ConfigTransformer{ 70 Concrete: b.ConcreteResource, 71 Module: b.Module, 72 }, 73 74 // Add the local values 75 &LocalTransformer{Module: b.Module}, 76 77 // Add the outputs 78 &OutputTransformer{Module: b.Module}, 79 80 // Add orphan resources 81 &OrphanResourceTransformer{ 82 Concrete: b.ConcreteResourceOrphan, 83 State: b.State, 84 Module: b.Module, 85 }, 86 87 // Attach the configuration to any resources 88 &AttachResourceConfigTransformer{Module: b.Module}, 89 90 // Attach the state 91 &AttachStateTransformer{State: b.State}, 92 93 // Add root variables 94 &RootVariableTransformer{Module: b.Module}, 95 96 TransformProviders(b.Providers, b.ConcreteProvider, b.Module), 97 98 // Provisioner-related transformations. Only add these if requested. 99 GraphTransformIf( 100 func() bool { return b.Provisioners != nil }, 101 GraphTransformMulti( 102 &MissingProvisionerTransformer{Provisioners: b.Provisioners}, 103 &ProvisionerTransformer{}, 104 ), 105 ), 106 107 // Add module variables 108 &ModuleVariableTransformer{ 109 Module: b.Module, 110 }, 111 112 // Connect so that the references are ready for targeting. We'll 113 // have to connect again later for providers and so on. 114 &ReferenceTransformer{}, 115 116 // Add the node to fix the state count boundaries 117 &CountBoundaryTransformer{}, 118 119 // Target 120 &TargetsTransformer{ 121 Targets: b.Targets, 122 123 // Resource nodes from config have not yet been expanded for 124 // "count", so we must apply targeting without indices. Exact 125 // targeting will be dealt with later when these resources 126 // DynamicExpand. 127 IgnoreIndices: true, 128 }, 129 130 // Close opened plugin connections 131 &CloseProviderTransformer{}, 132 &CloseProvisionerTransformer{}, 133 134 // Single root 135 &RootTransformer{}, 136 } 137 138 if !b.DisableReduce { 139 // Perform the transitive reduction to make our graph a bit 140 // more sane if possible (it usually is possible). 141 steps = append(steps, &TransitiveReductionTransformer{}) 142 } 143 144 return steps 145 } 146 147 func (b *PlanGraphBuilder) init() { 148 // Do nothing if the user requests customizing the fields 149 if b.CustomConcrete { 150 return 151 } 152 153 b.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex { 154 return &NodeApplyableProvider{ 155 NodeAbstractProvider: a, 156 } 157 } 158 159 b.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex { 160 return &NodePlannableResource{ 161 NodeAbstractCountResource: &NodeAbstractCountResource{ 162 NodeAbstractResource: a, 163 }, 164 } 165 } 166 167 b.ConcreteResourceOrphan = func(a *NodeAbstractResource) dag.Vertex { 168 return &NodePlannableResourceOrphan{ 169 NodeAbstractResource: a, 170 } 171 } 172 }