github.com/kanishk98/terraform@v1.3.0-dev.0.20220917174235-661ca8088a6a/internal/terraform/graph_builder_apply.go (about)

     1  package terraform
     2  
     3  import (
     4  	"github.com/hashicorp/terraform/internal/addrs"
     5  	"github.com/hashicorp/terraform/internal/configs"
     6  	"github.com/hashicorp/terraform/internal/dag"
     7  	"github.com/hashicorp/terraform/internal/plans"
     8  	"github.com/hashicorp/terraform/internal/states"
     9  	"github.com/hashicorp/terraform/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  	// RootVariableValues are the root module input variables captured as
    30  	// part of the plan object, which we must reproduce in the apply step
    31  	// to get a consistent result.
    32  	RootVariableValues InputValues
    33  
    34  	// Plugins is a library of the plug-in components (providers and
    35  	// provisioners) available for use.
    36  	Plugins *contextPlugins
    37  
    38  	// Targets are resources to target. This is only required to make sure
    39  	// unnecessary outputs aren't included in the apply graph. The plan
    40  	// builder successfully handles targeting resources. In the future,
    41  	// outputs should go into the diff so that this is unnecessary.
    42  	Targets []addrs.Targetable
    43  
    44  	// ForceReplace are the resource instance addresses that the user
    45  	// requested to force replacement for when creating the plan, if any.
    46  	// The apply step refers to these as part of verifying that the planned
    47  	// actions remain consistent between plan and apply.
    48  	ForceReplace []addrs.AbsResourceInstance
    49  }
    50  
    51  // See GraphBuilder
    52  func (b *ApplyGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) {
    53  	return (&BasicGraphBuilder{
    54  		Steps: b.Steps(),
    55  		Name:  "ApplyGraphBuilder",
    56  	}).Build(path)
    57  }
    58  
    59  // See GraphBuilder
    60  func (b *ApplyGraphBuilder) Steps() []GraphTransformer {
    61  	// Custom factory for creating providers.
    62  	concreteProvider := func(a *NodeAbstractProvider) dag.Vertex {
    63  		return &NodeApplyableProvider{
    64  			NodeAbstractProvider: a,
    65  		}
    66  	}
    67  
    68  	concreteResource := func(a *NodeAbstractResource) dag.Vertex {
    69  		return &nodeExpandApplyableResource{
    70  			NodeAbstractResource: a,
    71  		}
    72  	}
    73  
    74  	concreteResourceInstance := func(a *NodeAbstractResourceInstance) dag.Vertex {
    75  		return &NodeApplyableResourceInstance{
    76  			NodeAbstractResourceInstance: a,
    77  			forceReplace:                 b.ForceReplace,
    78  		}
    79  	}
    80  
    81  	steps := []GraphTransformer{
    82  		// Creates all the resources represented in the config. During apply,
    83  		// we use this just to ensure that the whole-resource metadata is
    84  		// updated to reflect things such as whether the count argument is
    85  		// set in config, or which provider configuration manages each resource.
    86  		&ConfigTransformer{
    87  			Concrete: concreteResource,
    88  			Config:   b.Config,
    89  		},
    90  
    91  		// Add dynamic values
    92  		&RootVariableTransformer{Config: b.Config, RawValues: b.RootVariableValues},
    93  		&ModuleVariableTransformer{Config: b.Config},
    94  		&LocalTransformer{Config: b.Config},
    95  		&OutputTransformer{Config: b.Config, Changes: b.Changes},
    96  
    97  		// Creates all the resource instances represented in the diff, along
    98  		// with dependency edges against the whole-resource nodes added by
    99  		// ConfigTransformer above.
   100  		&DiffTransformer{
   101  			Concrete: concreteResourceInstance,
   102  			State:    b.State,
   103  			Changes:  b.Changes,
   104  		},
   105  
   106  		// Attach the state
   107  		&AttachStateTransformer{State: b.State},
   108  
   109  		// Create orphan output nodes
   110  		&OrphanOutputTransformer{Config: b.Config, State: b.State},
   111  
   112  		// Attach the configuration to any resources
   113  		&AttachResourceConfigTransformer{Config: b.Config},
   114  
   115  		// add providers
   116  		transformProviders(concreteProvider, b.Config),
   117  
   118  		// Remove modules no longer present in the config
   119  		&RemovedModuleTransformer{Config: b.Config, State: b.State},
   120  
   121  		// Must attach schemas before ReferenceTransformer so that we can
   122  		// analyze the configuration to find references.
   123  		&AttachSchemaTransformer{Plugins: b.Plugins, Config: b.Config},
   124  
   125  		// Create expansion nodes for all of the module calls. This must
   126  		// come after all other transformers that create nodes representing
   127  		// objects that can belong to modules.
   128  		&ModuleExpansionTransformer{Config: b.Config},
   129  
   130  		// Connect references so ordering is correct
   131  		&ReferenceTransformer{},
   132  		&AttachDependenciesTransformer{},
   133  
   134  		// Detect when create_before_destroy must be forced on for a particular
   135  		// node due to dependency edges, to avoid graph cycles during apply.
   136  		&ForcedCBDTransformer{},
   137  
   138  		// Destruction ordering
   139  		&DestroyEdgeTransformer{},
   140  		&CBDEdgeTransformer{
   141  			Config: b.Config,
   142  			State:  b.State,
   143  		},
   144  
   145  		// We need to remove configuration nodes that are not used at all, as
   146  		// they may not be able to evaluate, especially during destroy.
   147  		// These include variables, locals, and instance expanders.
   148  		&pruneUnusedNodesTransformer{},
   149  
   150  		// Target
   151  		&TargetsTransformer{Targets: b.Targets},
   152  
   153  		// Close opened plugin connections
   154  		&CloseProviderTransformer{},
   155  
   156  		// close the root module
   157  		&CloseRootModuleTransformer{},
   158  
   159  		// Perform the transitive reduction to make our graph a bit
   160  		// more understandable if possible (it usually is possible).
   161  		&TransitiveReductionTransformer{},
   162  	}
   163  
   164  	return steps
   165  }