github.com/posener/terraform@v0.11.0-beta1.0.20171103235147-645df36af025/terraform/graph_builder_plan.go (about)

     1  package terraform
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/hashicorp/terraform/config/module"
     7  	"github.com/hashicorp/terraform/dag"
     8  )
     9  
    10  // PlanGraphBuilder implements GraphBuilder and is responsible for building
    11  // a graph for planning (creating a Terraform Diff).
    12  //
    13  // The primary difference between this graph and others:
    14  //
    15  //   * Based on the config since it represents the target state
    16  //
    17  //   * Ignores lifecycle options since no lifecycle events occur here. This
    18  //     simplifies the graph significantly since complex transforms such as
    19  //     create-before-destroy can be completely ignored.
    20  //
    21  type PlanGraphBuilder struct {
    22  	// Module is the root module for the graph to build.
    23  	Module *module.Tree
    24  
    25  	// State is the current state
    26  	State *State
    27  
    28  	// Providers is the list of providers supported.
    29  	Providers []string
    30  
    31  	// Provisioners is the list of provisioners supported.
    32  	Provisioners []string
    33  
    34  	// Targets are resources to target
    35  	Targets []string
    36  
    37  	// DisableReduce, if true, will not reduce the graph. Great for testing.
    38  	DisableReduce bool
    39  
    40  	// Validate will do structural validation of the graph.
    41  	Validate bool
    42  
    43  	// CustomConcrete can be set to customize the node types created
    44  	// for various parts of the plan. This is useful in order to customize
    45  	// the plan behavior.
    46  	CustomConcrete         bool
    47  	ConcreteProvider       ConcreteProviderNodeFunc
    48  	ConcreteResource       ConcreteResourceNodeFunc
    49  	ConcreteResourceOrphan ConcreteResourceNodeFunc
    50  
    51  	once sync.Once
    52  }
    53  
    54  // See GraphBuilder
    55  func (b *PlanGraphBuilder) Build(path []string) (*Graph, error) {
    56  	return (&BasicGraphBuilder{
    57  		Steps:    b.Steps(),
    58  		Validate: b.Validate,
    59  		Name:     "PlanGraphBuilder",
    60  	}).Build(path)
    61  }
    62  
    63  // See GraphBuilder
    64  func (b *PlanGraphBuilder) Steps() []GraphTransformer {
    65  	b.once.Do(b.init)
    66  
    67  	steps := []GraphTransformer{
    68  		// Creates all the resources represented in the config
    69  		&ConfigTransformer{
    70  			Concrete: b.ConcreteResource,
    71  			Module:   b.Module,
    72  		},
    73  
    74  		// Add the local values
    75  		&LocalTransformer{Module: b.Module},
    76  
    77  		// Add the outputs
    78  		&OutputTransformer{Module: b.Module},
    79  
    80  		// Add orphan resources
    81  		&OrphanResourceTransformer{
    82  			Concrete: b.ConcreteResourceOrphan,
    83  			State:    b.State,
    84  			Module:   b.Module,
    85  		},
    86  
    87  		// Attach the configuration to any resources
    88  		&AttachResourceConfigTransformer{Module: b.Module},
    89  
    90  		// Attach the state
    91  		&AttachStateTransformer{State: b.State},
    92  
    93  		// Add root variables
    94  		&RootVariableTransformer{Module: b.Module},
    95  
    96  		TransformProviders(b.Providers, b.ConcreteProvider, b.Module),
    97  
    98  		// Provisioner-related transformations. Only add these if requested.
    99  		GraphTransformIf(
   100  			func() bool { return b.Provisioners != nil },
   101  			GraphTransformMulti(
   102  				&MissingProvisionerTransformer{Provisioners: b.Provisioners},
   103  				&ProvisionerTransformer{},
   104  			),
   105  		),
   106  
   107  		// Add module variables
   108  		&ModuleVariableTransformer{
   109  			Module: b.Module,
   110  		},
   111  
   112  		// Connect so that the references are ready for targeting. We'll
   113  		// have to connect again later for providers and so on.
   114  		&ReferenceTransformer{},
   115  
   116  		// Add the node to fix the state count boundaries
   117  		&CountBoundaryTransformer{},
   118  
   119  		// Target
   120  		&TargetsTransformer{
   121  			Targets: b.Targets,
   122  
   123  			// Resource nodes from config have not yet been expanded for
   124  			// "count", so we must apply targeting without indices. Exact
   125  			// targeting will be dealt with later when these resources
   126  			// DynamicExpand.
   127  			IgnoreIndices: true,
   128  		},
   129  
   130  		// Close opened plugin connections
   131  		&CloseProviderTransformer{},
   132  		&CloseProvisionerTransformer{},
   133  
   134  		// Single root
   135  		&RootTransformer{},
   136  	}
   137  
   138  	if !b.DisableReduce {
   139  		// Perform the transitive reduction to make our graph a bit
   140  		// more sane if possible (it usually is possible).
   141  		steps = append(steps, &TransitiveReductionTransformer{})
   142  	}
   143  
   144  	return steps
   145  }
   146  
   147  func (b *PlanGraphBuilder) init() {
   148  	// Do nothing if the user requests customizing the fields
   149  	if b.CustomConcrete {
   150  		return
   151  	}
   152  
   153  	b.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex {
   154  		return &NodeApplyableProvider{
   155  			NodeAbstractProvider: a,
   156  		}
   157  	}
   158  
   159  	b.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex {
   160  		return &NodePlannableResource{
   161  			NodeAbstractCountResource: &NodeAbstractCountResource{
   162  				NodeAbstractResource: a,
   163  			},
   164  		}
   165  	}
   166  
   167  	b.ConcreteResourceOrphan = func(a *NodeAbstractResource) dag.Vertex {
   168  		return &NodePlannableResourceOrphan{
   169  			NodeAbstractResource: a,
   170  		}
   171  	}
   172  }