github.com/hashicorp/terraform-plugin-sdk@v1.17.2/terraform/graph_builder_apply.go (about) 1 package terraform 2 3 import ( 4 "github.com/hashicorp/terraform-plugin-sdk/internal/addrs" 5 "github.com/hashicorp/terraform-plugin-sdk/internal/configs" 6 "github.com/hashicorp/terraform-plugin-sdk/internal/dag" 7 "github.com/hashicorp/terraform-plugin-sdk/internal/plans" 8 "github.com/hashicorp/terraform-plugin-sdk/internal/states" 9 "github.com/hashicorp/terraform-plugin-sdk/internal/tfdiags" 10 ) 11 12 // ApplyGraphBuilder implements GraphBuilder and is responsible for building 13 // a graph for applying a Terraform diff. 14 // 15 // Because the graph is built from the diff (vs. the config or state), 16 // this helps ensure that the apply-time graph doesn't modify any resources 17 // that aren't explicitly in the diff. There are other scenarios where the 18 // diff can be deviated, so this is just one layer of protection. 19 type ApplyGraphBuilder struct { 20 // Config is the configuration tree that the diff was built from. 21 Config *configs.Config 22 23 // Changes describes the changes that we need apply. 24 Changes *plans.Changes 25 26 // State is the current state 27 State *states.State 28 29 // Components is a factory for the plug-in components (providers and 30 // provisioners) available for use. 31 Components contextComponentFactory 32 33 // Schemas is the repository of schemas we will draw from to analyse 34 // the configuration. 35 Schemas *Schemas 36 37 // Targets are resources to target. This is only required to make sure 38 // unnecessary outputs aren't included in the apply graph. The plan 39 // builder successfully handles targeting resources. In the future, 40 // outputs should go into the diff so that this is unnecessary. 41 Targets []addrs.Targetable 42 43 // DisableReduce, if true, will not reduce the graph. Great for testing. 44 DisableReduce bool 45 46 // Destroy, if true, represents a pure destroy operation 47 Destroy bool 48 49 // Validate will do structural validation of the graph. 50 Validate bool 51 } 52 53 // See GraphBuilder 54 func (b *ApplyGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) { 55 return (&BasicGraphBuilder{ 56 Steps: b.Steps(), 57 Validate: b.Validate, 58 Name: "ApplyGraphBuilder", 59 }).Build(path) 60 } 61 62 // See GraphBuilder 63 func (b *ApplyGraphBuilder) Steps() []GraphTransformer { 64 // Custom factory for creating providers. 65 concreteProvider := func(a *NodeAbstractProvider) dag.Vertex { 66 return &NodeApplyableProvider{ 67 NodeAbstractProvider: a, 68 } 69 } 70 71 concreteResource := func(a *NodeAbstractResource) dag.Vertex { 72 return &NodeApplyableResource{ 73 NodeAbstractResource: a, 74 } 75 } 76 77 concreteOrphanResource := func(a *NodeAbstractResource) dag.Vertex { 78 return &NodeDestroyResource{ 79 NodeAbstractResource: a, 80 } 81 } 82 83 concreteResourceInstance := func(a *NodeAbstractResourceInstance) dag.Vertex { 84 return &NodeApplyableResourceInstance{ 85 NodeAbstractResourceInstance: a, 86 } 87 } 88 89 steps := []GraphTransformer{ 90 // Creates all the resources represented in the config. During apply, 91 // we use this just to ensure that the whole-resource metadata is 92 // updated to reflect things such as whether the count argument is 93 // set in config, or which provider configuration manages each resource. 94 &ConfigTransformer{ 95 Concrete: concreteResource, 96 Config: b.Config, 97 }, 98 99 // Creates all the resource instances represented in the diff, along 100 // with dependency edges against the whole-resource nodes added by 101 // ConfigTransformer above. 102 &DiffTransformer{ 103 Concrete: concreteResourceInstance, 104 State: b.State, 105 Changes: b.Changes, 106 }, 107 108 // Creates extra cleanup nodes for any entire resources that are 109 // no longer present in config, so we can make sure we clean up the 110 // leftover empty resource states after the instances have been 111 // destroyed. 112 // (We don't track this particular type of change in the plan because 113 // it's just cleanup of our own state object, and so doesn't effect 114 // any real remote objects or consumable outputs.) 115 &OrphanResourceTransformer{ 116 Concrete: concreteOrphanResource, 117 Config: b.Config, 118 State: b.State, 119 }, 120 121 // Create orphan output nodes 122 &OrphanOutputTransformer{Config: b.Config, State: b.State}, 123 124 // Attach the configuration to any resources 125 &AttachResourceConfigTransformer{Config: b.Config}, 126 127 // Attach the state 128 &AttachStateTransformer{State: b.State}, 129 130 // Provisioner-related transformations 131 &MissingProvisionerTransformer{Provisioners: b.Components.ResourceProvisioners()}, 132 &ProvisionerTransformer{}, 133 134 // Add root variables 135 &RootVariableTransformer{Config: b.Config}, 136 137 // Add the local values 138 &LocalTransformer{Config: b.Config}, 139 140 // Add the outputs 141 &OutputTransformer{Config: b.Config}, 142 143 // Add module variables 144 &ModuleVariableTransformer{Config: b.Config}, 145 146 // add providers 147 TransformProviders(b.Components.ResourceProviders(), concreteProvider, b.Config), 148 149 // Remove modules no longer present in the config 150 &RemovedModuleTransformer{Config: b.Config, State: b.State}, 151 152 // Must attach schemas before ReferenceTransformer so that we can 153 // analyze the configuration to find references. 154 &AttachSchemaTransformer{Schemas: b.Schemas}, 155 156 // Connect references so ordering is correct 157 &ReferenceTransformer{}, 158 159 // Destruction ordering 160 &DestroyEdgeTransformer{ 161 Config: b.Config, 162 State: b.State, 163 Schemas: b.Schemas, 164 }, 165 166 &CBDEdgeTransformer{ 167 Config: b.Config, 168 State: b.State, 169 Schemas: b.Schemas, 170 Destroy: b.Destroy, 171 }, 172 173 // Handle destroy time transformations for output and local values. 174 // Reverse the edges from outputs and locals, so that 175 // interpolations don't fail during destroy. 176 // Create a destroy node for outputs to remove them from the state. 177 // Prune unreferenced values, which may have interpolations that can't 178 // be resolved. 179 GraphTransformIf( 180 func() bool { return b.Destroy }, 181 GraphTransformMulti( 182 &DestroyValueReferenceTransformer{}, 183 &DestroyOutputTransformer{}, 184 &PruneUnusedValuesTransformer{}, 185 ), 186 ), 187 188 // Add the node to fix the state count boundaries 189 &CountBoundaryTransformer{ 190 Config: b.Config, 191 }, 192 193 // Target 194 &TargetsTransformer{Targets: b.Targets}, 195 196 // Close opened plugin connections 197 &CloseProviderTransformer{}, 198 &CloseProvisionerTransformer{}, 199 200 // Single root 201 &RootTransformer{}, 202 } 203 204 if !b.DisableReduce { 205 // Perform the transitive reduction to make our graph a bit 206 // more sane if possible (it usually is possible). 207 steps = append(steps, &TransitiveReductionTransformer{}) 208 } 209 210 return steps 211 }