github.com/opentofu/opentofu@v1.7.1/internal/tofu/graph_builder_apply.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package tofu 7 8 import ( 9 "github.com/opentofu/opentofu/internal/addrs" 10 "github.com/opentofu/opentofu/internal/configs" 11 "github.com/opentofu/opentofu/internal/dag" 12 "github.com/opentofu/opentofu/internal/plans" 13 "github.com/opentofu/opentofu/internal/states" 14 "github.com/opentofu/opentofu/internal/tfdiags" 15 ) 16 17 // ApplyGraphBuilder implements GraphBuilder and is responsible for building 18 // a graph for applying a OpenTofu diff. 19 // 20 // Because the graph is built from the diff (vs. the config or state), 21 // this helps ensure that the apply-time graph doesn't modify any resources 22 // that aren't explicitly in the diff. There are other scenarios where the 23 // diff can be deviated, so this is just one layer of protection. 24 type ApplyGraphBuilder struct { 25 // Config is the configuration tree that the diff was built from. 26 Config *configs.Config 27 28 // Changes describes the changes that we need apply. 29 Changes *plans.Changes 30 31 // State is the current state 32 State *states.State 33 34 // RootVariableValues are the root module input variables captured as 35 // part of the plan object, which we must reproduce in the apply step 36 // to get a consistent result. 37 RootVariableValues InputValues 38 39 // Plugins is a library of the plug-in components (providers and 40 // provisioners) available for use. 41 Plugins *contextPlugins 42 43 // Targets are resources to target. This is only required to make sure 44 // unnecessary outputs aren't included in the apply graph. The plan 45 // builder successfully handles targeting resources. In the future, 46 // outputs should go into the diff so that this is unnecessary. 47 Targets []addrs.Targetable 48 49 // ForceReplace are the resource instance addresses that the user 50 // requested to force replacement for when creating the plan, if any. 51 // The apply step refers to these as part of verifying that the planned 52 // actions remain consistent between plan and apply. 53 ForceReplace []addrs.AbsResourceInstance 54 55 // Plan Operation this graph will be used for. 56 Operation walkOperation 57 58 // ExternalReferences allows the external caller to pass in references to 59 // nodes that should not be pruned even if they are not referenced within 60 // the actual graph. 61 ExternalReferences []*addrs.Reference 62 } 63 64 // See GraphBuilder 65 func (b *ApplyGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) { 66 return (&BasicGraphBuilder{ 67 Steps: b.Steps(), 68 Name: "ApplyGraphBuilder", 69 }).Build(path) 70 } 71 72 // See GraphBuilder 73 func (b *ApplyGraphBuilder) Steps() []GraphTransformer { 74 // Custom factory for creating providers. 75 concreteProvider := func(a *NodeAbstractProvider) dag.Vertex { 76 return &NodeApplyableProvider{ 77 NodeAbstractProvider: a, 78 } 79 } 80 81 concreteResource := func(a *NodeAbstractResource) dag.Vertex { 82 return &nodeExpandApplyableResource{ 83 NodeAbstractResource: a, 84 } 85 } 86 87 concreteResourceInstance := func(a *NodeAbstractResourceInstance) dag.Vertex { 88 return &NodeApplyableResourceInstance{ 89 NodeAbstractResourceInstance: a, 90 forceReplace: b.ForceReplace, 91 } 92 } 93 94 steps := []GraphTransformer{ 95 // Creates all the resources represented in the config. During apply, 96 // we use this just to ensure that the whole-resource metadata is 97 // updated to reflect things such as whether the count argument is 98 // set in config, or which provider configuration manages each resource. 99 &ConfigTransformer{ 100 Concrete: concreteResource, 101 Config: b.Config, 102 }, 103 104 // Add dynamic values 105 &RootVariableTransformer{Config: b.Config, RawValues: b.RootVariableValues}, 106 &ModuleVariableTransformer{Config: b.Config}, 107 &LocalTransformer{Config: b.Config}, 108 &OutputTransformer{ 109 Config: b.Config, 110 Destroying: b.Operation == walkDestroy, 111 }, 112 113 // Creates all the resource instances represented in the diff, along 114 // with dependency edges against the whole-resource nodes added by 115 // ConfigTransformer above. 116 &DiffTransformer{ 117 Concrete: concreteResourceInstance, 118 State: b.State, 119 Changes: b.Changes, 120 Config: b.Config, 121 }, 122 123 // Add nodes and edges for check block assertions. Check block data 124 // sources were added earlier. 125 &checkTransformer{ 126 Config: b.Config, 127 Operation: b.Operation, 128 }, 129 130 // Attach the state 131 &AttachStateTransformer{State: b.State}, 132 133 // Create orphan output nodes 134 &OrphanOutputTransformer{Config: b.Config, State: b.State}, 135 136 // Attach the configuration to any resources 137 &AttachResourceConfigTransformer{Config: b.Config}, 138 139 // add providers 140 transformProviders(concreteProvider, b.Config), 141 142 // Remove modules no longer present in the config 143 &RemovedModuleTransformer{Config: b.Config, State: b.State}, 144 145 // Must attach schemas before ReferenceTransformer so that we can 146 // analyze the configuration to find references. 147 &AttachSchemaTransformer{Plugins: b.Plugins, Config: b.Config}, 148 149 // After schema transformer, we can add function references 150 &ProviderFunctionTransformer{Config: b.Config}, 151 152 // Remove unused providers and proxies 153 &PruneProviderTransformer{}, 154 155 // Create expansion nodes for all of the module calls. This must 156 // come after all other transformers that create nodes representing 157 // objects that can belong to modules. 158 &ModuleExpansionTransformer{Config: b.Config}, 159 160 // Plug in any external references. 161 &ExternalReferenceTransformer{ 162 ExternalReferences: b.ExternalReferences, 163 }, 164 165 // Connect references so ordering is correct 166 &ReferenceTransformer{}, 167 &AttachDependenciesTransformer{}, 168 169 // Nested data blocks should be loaded after every other resource has 170 // done its thing. 171 &checkStartTransformer{Config: b.Config, Operation: b.Operation}, 172 173 // Detect when create_before_destroy must be forced on for a particular 174 // node due to dependency edges, to avoid graph cycles during apply. 175 &ForcedCBDTransformer{}, 176 177 // Destruction ordering 178 &DestroyEdgeTransformer{ 179 Changes: b.Changes, 180 Operation: b.Operation, 181 }, 182 &CBDEdgeTransformer{ 183 Config: b.Config, 184 State: b.State, 185 }, 186 187 // We need to remove configuration nodes that are not used at all, as 188 // they may not be able to evaluate, especially during destroy. 189 // These include variables, locals, and instance expanders. 190 &pruneUnusedNodesTransformer{}, 191 192 // Target 193 &TargetsTransformer{Targets: b.Targets}, 194 195 // Close opened plugin connections 196 &CloseProviderTransformer{}, 197 198 // close the root module 199 &CloseRootModuleTransformer{}, 200 201 // Perform the transitive reduction to make our graph a bit 202 // more understandable if possible (it usually is possible). 203 &TransitiveReductionTransformer{}, 204 } 205 206 return steps 207 }