github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/terraform/graph_builder_plan.go (about)

     1  package terraform
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/hashicorp/terraform/addrs"
     7  	"github.com/hashicorp/terraform/configs"
     8  	"github.com/hashicorp/terraform/dag"
     9  	"github.com/hashicorp/terraform/states"
    10  	"github.com/hashicorp/terraform/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  	// Components is a factory for the plug-in components (providers and
    32  	// provisioners) available for use.
    33  	Components contextComponentFactory
    34  
    35  	// Schemas is the repository of schemas we will draw from to analyse
    36  	// the configuration.
    37  	Schemas *Schemas
    38  
    39  	// Targets are resources to target
    40  	Targets []addrs.Targetable
    41  
    42  	// DisableReduce, if true, will not reduce the graph. Great for testing.
    43  	DisableReduce bool
    44  
    45  	// Validate will do structural validation of the graph.
    46  	Validate bool
    47  
    48  	// CustomConcrete can be set to customize the node types created
    49  	// for various parts of the plan. This is useful in order to customize
    50  	// the plan behavior.
    51  	CustomConcrete         bool
    52  	ConcreteProvider       ConcreteProviderNodeFunc
    53  	ConcreteResource       ConcreteResourceNodeFunc
    54  	ConcreteResourceOrphan ConcreteResourceInstanceNodeFunc
    55  
    56  	once sync.Once
    57  }
    58  
    59  // See GraphBuilder
    60  func (b *PlanGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) {
    61  	return (&BasicGraphBuilder{
    62  		Steps:    b.Steps(),
    63  		Validate: b.Validate,
    64  		Name:     "PlanGraphBuilder",
    65  	}).Build(path)
    66  }
    67  
    68  // See GraphBuilder
    69  func (b *PlanGraphBuilder) Steps() []GraphTransformer {
    70  	b.once.Do(b.init)
    71  
    72  	concreteResourceInstanceDeposed := func(a *NodeAbstractResourceInstance, key states.DeposedKey) dag.Vertex {
    73  		return &NodePlanDeposedResourceInstanceObject{
    74  			NodeAbstractResourceInstance: a,
    75  			DeposedKey:                   key,
    76  		}
    77  	}
    78  
    79  	steps := []GraphTransformer{
    80  		// Creates all the resources represented in the config
    81  		&ConfigTransformer{
    82  			Concrete: b.ConcreteResource,
    83  			Config:   b.Config,
    84  		},
    85  
    86  		// Add the local values
    87  		&LocalTransformer{Config: b.Config},
    88  
    89  		// Add the outputs
    90  		&OutputTransformer{Config: b.Config},
    91  
    92  		// Add orphan resources
    93  		&OrphanResourceInstanceTransformer{
    94  			Concrete: b.ConcreteResourceOrphan,
    95  			State:    b.State,
    96  			Config:   b.Config,
    97  		},
    98  
    99  		// We also need nodes for any deposed instance objects present in the
   100  		// state, so we can plan to destroy them. (This intentionally
   101  		// skips creating nodes for _current_ objects, since ConfigTransformer
   102  		// created nodes that will do that during DynamicExpand.)
   103  		&StateTransformer{
   104  			ConcreteDeposed: concreteResourceInstanceDeposed,
   105  			State:           b.State,
   106  		},
   107  
   108  		// Create orphan output nodes
   109  		&OrphanOutputTransformer{
   110  			Config: b.Config,
   111  			State:  b.State,
   112  		},
   113  
   114  		// Attach the configuration to any resources
   115  		&AttachResourceConfigTransformer{Config: b.Config},
   116  
   117  		// Attach the state
   118  		&AttachStateTransformer{State: b.State},
   119  
   120  		// Add root variables
   121  		&RootVariableTransformer{Config: b.Config},
   122  
   123  		&MissingProvisionerTransformer{Provisioners: b.Components.ResourceProvisioners()},
   124  		&ProvisionerTransformer{},
   125  
   126  		// Add module variables
   127  		&ModuleVariableTransformer{
   128  			Config: b.Config,
   129  		},
   130  
   131  		TransformProviders(b.Components.ResourceProviders(), b.ConcreteProvider, b.Config),
   132  
   133  		// Remove modules no longer present in the config
   134  		&RemovedModuleTransformer{Config: b.Config, State: b.State},
   135  
   136  		// Must attach schemas before ReferenceTransformer so that we can
   137  		// analyze the configuration to find references.
   138  		&AttachSchemaTransformer{Schemas: b.Schemas},
   139  
   140  		// Connect so that the references are ready for targeting. We'll
   141  		// have to connect again later for providers and so on.
   142  		&ReferenceTransformer{},
   143  
   144  		// Add the node to fix the state count boundaries
   145  		&CountBoundaryTransformer{
   146  			Config: b.Config,
   147  		},
   148  
   149  		// Target
   150  		&TargetsTransformer{
   151  			Targets: b.Targets,
   152  
   153  			// Resource nodes from config have not yet been expanded for
   154  			// "count", so we must apply targeting without indices. Exact
   155  			// targeting will be dealt with later when these resources
   156  			// DynamicExpand.
   157  			IgnoreIndices: true,
   158  		},
   159  
   160  		// Detect when create_before_destroy must be forced on for a particular
   161  		// node due to dependency edges, to avoid graph cycles during apply.
   162  		&ForcedCBDTransformer{},
   163  
   164  		// Close opened plugin connections
   165  		&CloseProviderTransformer{},
   166  		&CloseProvisionerTransformer{},
   167  
   168  		// Single root
   169  		&RootTransformer{},
   170  	}
   171  
   172  	if !b.DisableReduce {
   173  		// Perform the transitive reduction to make our graph a bit
   174  		// more sane if possible (it usually is possible).
   175  		steps = append(steps, &TransitiveReductionTransformer{})
   176  	}
   177  
   178  	return steps
   179  }
   180  
   181  func (b *PlanGraphBuilder) init() {
   182  	// Do nothing if the user requests customizing the fields
   183  	if b.CustomConcrete {
   184  		return
   185  	}
   186  
   187  	b.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex {
   188  		return &NodeApplyableProvider{
   189  			NodeAbstractProvider: a,
   190  		}
   191  	}
   192  
   193  	b.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex {
   194  		return &NodePlannableResource{
   195  			NodeAbstractResource: a,
   196  		}
   197  	}
   198  
   199  	b.ConcreteResourceOrphan = func(a *NodeAbstractResourceInstance) dag.Vertex {
   200  		return &NodePlannableResourceInstanceOrphan{
   201  			NodeAbstractResourceInstance: a,
   202  		}
   203  	}
   204  }