github.com/jaredpalmer/terraform@v1.1.0-alpha20210908.0.20210911170307-88705c943a03/internal/terraform/graph_builder_plan.go (about) 1 package terraform 2 3 import ( 4 "sync" 5 6 "github.com/hashicorp/terraform/internal/addrs" 7 "github.com/hashicorp/terraform/internal/configs" 8 "github.com/hashicorp/terraform/internal/dag" 9 "github.com/hashicorp/terraform/internal/states" 10 "github.com/hashicorp/terraform/internal/tfdiags" 11 ) 12 13 // PlanGraphBuilder implements GraphBuilder and is responsible for building 14 // a graph for planning (creating a Terraform Diff). 15 // 16 // The primary difference between this graph and others: 17 // 18 // * Based on the config since it represents the target state 19 // 20 // * Ignores lifecycle options since no lifecycle events occur here. This 21 // simplifies the graph significantly since complex transforms such as 22 // create-before-destroy can be completely ignored. 23 // 24 type PlanGraphBuilder struct { 25 // Config is the configuration tree to build a plan from. 26 Config *configs.Config 27 28 // State is the current state 29 State *states.State 30 31 // Plugins is a library of plug-in components (providers and 32 // provisioners) available for use. 33 Plugins *contextPlugins 34 35 // Targets are resources to target 36 Targets []addrs.Targetable 37 38 // ForceReplace are resource instances where if we would normally have 39 // generated a NoOp or Update action then we'll force generating a replace 40 // action instead. Create and Delete actions are not affected. 41 ForceReplace []addrs.AbsResourceInstance 42 43 // Validate will do structural validation of the graph. 44 Validate bool 45 46 // skipRefresh indicates that we should skip refreshing managed resources 47 skipRefresh bool 48 49 // skipPlanChanges indicates that we should skip the step of comparing 50 // prior state with configuration and generating planned changes to 51 // resource instances. (This is for the "refresh only" planning mode, 52 // where we _only_ do the refresh step.) 53 skipPlanChanges bool 54 55 // CustomConcrete can be set to customize the node types created 56 // for various parts of the plan. This is useful in order to customize 57 // the plan behavior. 58 CustomConcrete bool 59 ConcreteProvider ConcreteProviderNodeFunc 60 ConcreteResource ConcreteResourceNodeFunc 61 ConcreteResourceOrphan ConcreteResourceInstanceNodeFunc 62 ConcreteModule ConcreteModuleNodeFunc 63 64 once sync.Once 65 } 66 67 // See GraphBuilder 68 func (b *PlanGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) { 69 return (&BasicGraphBuilder{ 70 Steps: b.Steps(), 71 Validate: b.Validate, 72 Name: "PlanGraphBuilder", 73 }).Build(path) 74 } 75 76 // See GraphBuilder 77 func (b *PlanGraphBuilder) Steps() []GraphTransformer { 78 b.once.Do(b.init) 79 80 concreteResourceInstanceDeposed := func(a *NodeAbstractResourceInstance, key states.DeposedKey) dag.Vertex { 81 return &NodePlanDeposedResourceInstanceObject{ 82 NodeAbstractResourceInstance: a, 83 DeposedKey: key, 84 85 skipRefresh: b.skipRefresh, 86 skipPlanChanges: b.skipPlanChanges, 87 } 88 } 89 90 steps := []GraphTransformer{ 91 // Creates all the resources represented in the config 92 &ConfigTransformer{ 93 Concrete: b.ConcreteResource, 94 Config: b.Config, 95 }, 96 97 // Add dynamic values 98 &RootVariableTransformer{Config: b.Config}, 99 &ModuleVariableTransformer{Config: b.Config}, 100 &LocalTransformer{Config: b.Config}, 101 &OutputTransformer{Config: b.Config}, 102 103 // Add orphan resources 104 &OrphanResourceInstanceTransformer{ 105 Concrete: b.ConcreteResourceOrphan, 106 State: b.State, 107 Config: b.Config, 108 }, 109 110 // We also need nodes for any deposed instance objects present in the 111 // state, so we can plan to destroy them. (This intentionally 112 // skips creating nodes for _current_ objects, since ConfigTransformer 113 // created nodes that will do that during DynamicExpand.) 114 &StateTransformer{ 115 ConcreteDeposed: concreteResourceInstanceDeposed, 116 State: b.State, 117 }, 118 119 // Attach the state 120 &AttachStateTransformer{State: b.State}, 121 122 // Create orphan output nodes 123 &OrphanOutputTransformer{Config: b.Config, State: b.State}, 124 125 // Attach the configuration to any resources 126 &AttachResourceConfigTransformer{Config: b.Config}, 127 128 // add providers 129 transformProviders(b.ConcreteProvider, b.Config), 130 131 // Remove modules no longer present in the config 132 &RemovedModuleTransformer{Config: b.Config, State: b.State}, 133 134 // Must attach schemas before ReferenceTransformer so that we can 135 // analyze the configuration to find references. 136 &AttachSchemaTransformer{Plugins: b.Plugins, Config: b.Config}, 137 138 // Create expansion nodes for all of the module calls. This must 139 // come after all other transformers that create nodes representing 140 // objects that can belong to modules. 141 &ModuleExpansionTransformer{Concrete: b.ConcreteModule, Config: b.Config}, 142 143 // Connect so that the references are ready for targeting. We'll 144 // have to connect again later for providers and so on. 145 &ReferenceTransformer{}, 146 &AttachDependenciesTransformer{}, 147 148 // Make sure data sources are aware of any depends_on from the 149 // configuration 150 &attachDataResourceDependsOnTransformer{}, 151 152 // Target 153 &TargetsTransformer{Targets: b.Targets}, 154 155 // Detect when create_before_destroy must be forced on for a particular 156 // node due to dependency edges, to avoid graph cycles during apply. 157 &ForcedCBDTransformer{}, 158 159 // Add the node to fix the state count boundaries 160 &CountBoundaryTransformer{ 161 Config: b.Config, 162 }, 163 164 // Close opened plugin connections 165 &CloseProviderTransformer{}, 166 167 // Close the root module 168 &CloseRootModuleTransformer{}, 169 170 // Perform the transitive reduction to make our graph a bit 171 // more understandable if possible (it usually is possible). 172 &TransitiveReductionTransformer{}, 173 } 174 175 return steps 176 } 177 178 func (b *PlanGraphBuilder) init() { 179 // Do nothing if the user requests customizing the fields 180 if b.CustomConcrete { 181 return 182 } 183 184 b.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex { 185 return &NodeApplyableProvider{ 186 NodeAbstractProvider: a, 187 } 188 } 189 190 b.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex { 191 return &nodeExpandPlannableResource{ 192 NodeAbstractResource: a, 193 skipRefresh: b.skipRefresh, 194 skipPlanChanges: b.skipPlanChanges, 195 forceReplace: b.ForceReplace, 196 } 197 } 198 199 b.ConcreteResourceOrphan = func(a *NodeAbstractResourceInstance) dag.Vertex { 200 return &NodePlannableResourceInstanceOrphan{ 201 NodeAbstractResourceInstance: a, 202 skipRefresh: b.skipRefresh, 203 skipPlanChanges: b.skipPlanChanges, 204 } 205 } 206 }