github.com/hashicorp/terraform-plugin-sdk@v1.17.2/terraform/graph_builder_refresh.go (about)

     1  package terraform
     2  
     3  import (
     4  	"log"
     5  
     6  	"github.com/hashicorp/terraform-plugin-sdk/internal/states"
     7  	"github.com/hashicorp/terraform-plugin-sdk/internal/tfdiags"
     8  
     9  	"github.com/hashicorp/terraform-plugin-sdk/internal/addrs"
    10  	"github.com/hashicorp/terraform-plugin-sdk/internal/configs"
    11  	"github.com/hashicorp/terraform-plugin-sdk/internal/dag"
    12  )
    13  
    14  // RefreshGraphBuilder implements GraphBuilder and is responsible for building
    15  // a graph for refreshing (updating the Terraform state).
    16  //
    17  // The primary difference between this graph and others:
    18  //
    19  //   * Based on the state since it represents the only resources that
    20  //     need to be refreshed.
    21  //
    22  //   * Ignores lifecycle options since no lifecycle events occur here. This
    23  //     simplifies the graph significantly since complex transforms such as
    24  //     create-before-destroy can be completely ignored.
    25  //
    26  type RefreshGraphBuilder struct {
    27  	// Config is the configuration tree.
    28  	Config *configs.Config
    29  
    30  	// State is the prior state
    31  	State *states.State
    32  
    33  	// Components is a factory for the plug-in components (providers and
    34  	// provisioners) available for use.
    35  	Components contextComponentFactory
    36  
    37  	// Schemas is the repository of schemas we will draw from to analyse
    38  	// the configuration.
    39  	Schemas *Schemas
    40  
    41  	// Targets are resources to target
    42  	Targets []addrs.Targetable
    43  
    44  	// DisableReduce, if true, will not reduce the graph. Great for testing.
    45  	DisableReduce bool
    46  
    47  	// Validate will do structural validation of the graph.
    48  	Validate bool
    49  }
    50  
    51  // See GraphBuilder
    52  func (b *RefreshGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) {
    53  	return (&BasicGraphBuilder{
    54  		Steps:    b.Steps(),
    55  		Validate: b.Validate,
    56  		Name:     "RefreshGraphBuilder",
    57  	}).Build(path)
    58  }
    59  
    60  // See GraphBuilder
    61  func (b *RefreshGraphBuilder) Steps() []GraphTransformer {
    62  	// Custom factory for creating providers.
    63  	concreteProvider := func(a *NodeAbstractProvider) dag.Vertex {
    64  		return &NodeApplyableProvider{
    65  			NodeAbstractProvider: a,
    66  		}
    67  	}
    68  
    69  	concreteManagedResource := func(a *NodeAbstractResource) dag.Vertex {
    70  		return &NodeRefreshableManagedResource{
    71  			NodeAbstractResource: a,
    72  		}
    73  	}
    74  
    75  	concreteManagedResourceInstance := func(a *NodeAbstractResourceInstance) dag.Vertex {
    76  		return &NodeRefreshableManagedResourceInstance{
    77  			NodeAbstractResourceInstance: a,
    78  		}
    79  	}
    80  
    81  	concreteResourceInstanceDeposed := func(a *NodeAbstractResourceInstance, key states.DeposedKey) dag.Vertex {
    82  		// The "Plan" node type also handles refreshing behavior.
    83  		return &NodePlanDeposedResourceInstanceObject{
    84  			NodeAbstractResourceInstance: a,
    85  			DeposedKey:                   key,
    86  		}
    87  	}
    88  
    89  	concreteDataResource := func(a *NodeAbstractResource) dag.Vertex {
    90  		return &NodeRefreshableDataResource{
    91  			NodeAbstractResource: a,
    92  		}
    93  	}
    94  
    95  	steps := []GraphTransformer{
    96  		// Creates all the managed resources that aren't in the state, but only if
    97  		// we have a state already. No resources in state means there's not
    98  		// anything to refresh.
    99  		func() GraphTransformer {
   100  			if b.State.HasResources() {
   101  				return &ConfigTransformer{
   102  					Concrete:   concreteManagedResource,
   103  					Config:     b.Config,
   104  					Unique:     true,
   105  					ModeFilter: true,
   106  					Mode:       addrs.ManagedResourceMode,
   107  				}
   108  			}
   109  			log.Println("[TRACE] No managed resources in state during refresh; skipping managed resource transformer")
   110  			return nil
   111  		}(),
   112  
   113  		// Creates all the data resources that aren't in the state. This will also
   114  		// add any orphans from scaling in as destroy nodes.
   115  		&ConfigTransformer{
   116  			Concrete:   concreteDataResource,
   117  			Config:     b.Config,
   118  			Unique:     true,
   119  			ModeFilter: true,
   120  			Mode:       addrs.DataResourceMode,
   121  		},
   122  
   123  		// Add any fully-orphaned resources from config (ones that have been
   124  		// removed completely, not ones that are just orphaned due to a scaled-in
   125  		// count.
   126  		&OrphanResourceInstanceTransformer{
   127  			Concrete: concreteManagedResourceInstance,
   128  			State:    b.State,
   129  			Config:   b.Config,
   130  		},
   131  
   132  		// We also need nodes for any deposed instance objects present in the
   133  		// state, so we can check if they still exist. (This intentionally
   134  		// skips creating nodes for _current_ objects, since ConfigTransformer
   135  		// created nodes that will do that during DynamicExpand.)
   136  		&StateTransformer{
   137  			ConcreteDeposed: concreteResourceInstanceDeposed,
   138  			State:           b.State,
   139  		},
   140  
   141  		// Attach the state
   142  		&AttachStateTransformer{State: b.State},
   143  
   144  		// Attach the configuration to any resources
   145  		&AttachResourceConfigTransformer{Config: b.Config},
   146  
   147  		// Add root variables
   148  		&RootVariableTransformer{Config: b.Config},
   149  
   150  		// Add the local values
   151  		&LocalTransformer{Config: b.Config},
   152  
   153  		// Add the outputs
   154  		&OutputTransformer{Config: b.Config},
   155  
   156  		// Add module variables
   157  		&ModuleVariableTransformer{Config: b.Config},
   158  
   159  		TransformProviders(b.Components.ResourceProviders(), concreteProvider, b.Config),
   160  
   161  		// Must attach schemas before ReferenceTransformer so that we can
   162  		// analyze the configuration to find references.
   163  		&AttachSchemaTransformer{Schemas: b.Schemas},
   164  
   165  		// Connect so that the references are ready for targeting. We'll
   166  		// have to connect again later for providers and so on.
   167  		&ReferenceTransformer{},
   168  
   169  		// Target
   170  		&TargetsTransformer{
   171  			Targets: b.Targets,
   172  
   173  			// Resource nodes from config have not yet been expanded for
   174  			// "count", so we must apply targeting without indices. Exact
   175  			// targeting will be dealt with later when these resources
   176  			// DynamicExpand.
   177  			IgnoreIndices: true,
   178  		},
   179  
   180  		// Close opened plugin connections
   181  		&CloseProviderTransformer{},
   182  
   183  		// Single root
   184  		&RootTransformer{},
   185  	}
   186  
   187  	if !b.DisableReduce {
   188  		// Perform the transitive reduction to make our graph a bit
   189  		// more sane if possible (it usually is possible).
   190  		steps = append(steps, &TransitiveReductionTransformer{})
   191  	}
   192  
   193  	return steps
   194  }