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  }