github.com/hugorut/terraform@v1.1.3/src/terraform/context_walk.go (about)

     1  package terraform
     2  
     3  import (
     4  	"log"
     5  
     6  	"github.com/hugorut/terraform/src/configs"
     7  	"github.com/hugorut/terraform/src/instances"
     8  	"github.com/hugorut/terraform/src/plans"
     9  	"github.com/hugorut/terraform/src/refactoring"
    10  	"github.com/hugorut/terraform/src/states"
    11  	"github.com/hugorut/terraform/src/tfdiags"
    12  )
    13  
    14  // graphWalkOpts captures some transient values we use (and possibly mutate)
    15  // during a graph walk.
    16  //
    17  // The way these options get used unfortunately varies between the different
    18  // walkOperation types. This is a historical design wart that dates back to
    19  // us using the same graph structure for all operations; hopefully we'll
    20  // make the necessary differences between the walk types more explicit someday.
    21  type graphWalkOpts struct {
    22  	InputState *states.State
    23  	Changes    *plans.Changes
    24  	Config     *configs.Config
    25  
    26  	RootVariableValues InputValues
    27  	MoveResults        refactoring.MoveResults
    28  }
    29  
    30  func (c *Context) walk(graph *Graph, operation walkOperation, opts *graphWalkOpts) (*ContextGraphWalker, tfdiags.Diagnostics) {
    31  	log.Printf("[DEBUG] Starting graph walk: %s", operation.String())
    32  
    33  	walker := c.graphWalker(operation, opts)
    34  
    35  	// Watch for a stop so we can call the provider Stop() API.
    36  	watchStop, watchWait := c.watchStop(walker)
    37  
    38  	// Walk the real graph, this will block until it completes
    39  	diags := graph.Walk(walker)
    40  
    41  	// Close the channel so the watcher stops, and wait for it to return.
    42  	close(watchStop)
    43  	<-watchWait
    44  
    45  	return walker, diags
    46  }
    47  
    48  func (c *Context) graphWalker(operation walkOperation, opts *graphWalkOpts) *ContextGraphWalker {
    49  	var state *states.SyncState
    50  	var refreshState *states.SyncState
    51  	var prevRunState *states.SyncState
    52  
    53  	// NOTE: None of the SyncState objects must directly wrap opts.InputState,
    54  	// because we use those to mutate the state object and opts.InputState
    55  	// belongs to our caller and thus we must treat it as immutable.
    56  	//
    57  	// To account for that, most of our SyncState values created below end up
    58  	// wrapping a _deep copy_ of opts.InputState instead.
    59  	inputState := opts.InputState
    60  	if inputState == nil {
    61  		// Lots of callers use nil to represent the "empty" case where we've
    62  		// not run Apply yet, so we tolerate that.
    63  		inputState = states.NewState()
    64  	}
    65  
    66  	switch operation {
    67  	case walkValidate:
    68  		// validate should not use any state
    69  		state = states.NewState().SyncWrapper()
    70  
    71  		// validate currently uses the plan graph, so we have to populate the
    72  		// refreshState and the prevRunState.
    73  		refreshState = states.NewState().SyncWrapper()
    74  		prevRunState = states.NewState().SyncWrapper()
    75  
    76  	case walkPlan, walkPlanDestroy:
    77  		state = inputState.DeepCopy().SyncWrapper()
    78  		refreshState = inputState.DeepCopy().SyncWrapper()
    79  		prevRunState = inputState.DeepCopy().SyncWrapper()
    80  
    81  	default:
    82  		state = inputState.DeepCopy().SyncWrapper()
    83  		// Only plan-like walks use refreshState and prevRunState
    84  	}
    85  
    86  	changes := opts.Changes
    87  	if changes == nil {
    88  		// Several of our non-plan walks end up sharing codepaths with the
    89  		// plan walk and thus expect to generate planned changes even though
    90  		// we don't care about them. To avoid those crashing, we'll just
    91  		// insert a placeholder changes object which'll get discarded
    92  		// afterwards.
    93  		changes = plans.NewChanges()
    94  	}
    95  
    96  	if opts.Config == nil {
    97  		panic("Context.graphWalker call without Config")
    98  	}
    99  
   100  	return &ContextGraphWalker{
   101  		Context:            c,
   102  		State:              state,
   103  		Config:             opts.Config,
   104  		RefreshState:       refreshState,
   105  		PrevRunState:       prevRunState,
   106  		Changes:            changes.SyncWrapper(),
   107  		InstanceExpander:   instances.NewExpander(),
   108  		MoveResults:        opts.MoveResults,
   109  		Operation:          operation,
   110  		StopContext:        c.runContext,
   111  		RootVariableValues: opts.RootVariableValues,
   112  	}
   113  }