github.com/nicgrayson/terraform@v0.4.3-0.20150415203910-c4de50829380/terraform/graph_builder.go (about)

     1  package terraform
     2  
     3  import (
     4  	"log"
     5  
     6  	"github.com/hashicorp/terraform/config/module"
     7  )
     8  
     9  // GraphBuilder is an interface that can be implemented and used with
    10  // Terraform to build the graph that Terraform walks.
    11  type GraphBuilder interface {
    12  	// Build builds the graph for the given module path. It is up to
    13  	// the interface implementation whether this build should expand
    14  	// the graph or not.
    15  	Build(path []string) (*Graph, error)
    16  }
    17  
    18  // BasicGraphBuilder is a GraphBuilder that builds a graph out of a
    19  // series of transforms and validates the graph is a valid structure.
    20  type BasicGraphBuilder struct {
    21  	Steps []GraphTransformer
    22  }
    23  
    24  func (b *BasicGraphBuilder) Build(path []string) (*Graph, error) {
    25  	g := &Graph{Path: path}
    26  	for _, step := range b.Steps {
    27  		if err := step.Transform(g); err != nil {
    28  			return g, err
    29  		}
    30  
    31  		log.Printf(
    32  			"[TRACE] Graph after step %T:\n\n%s",
    33  			step, g.String())
    34  	}
    35  
    36  	// Validate the graph structure
    37  	if err := g.Validate(); err != nil {
    38  		log.Printf("[ERROR] Graph validation failed. Graph:\n\n%s", g.String())
    39  		return nil, err
    40  	}
    41  
    42  	return g, nil
    43  }
    44  
    45  // BuiltinGraphBuilder is responsible for building the complete graph that
    46  // Terraform uses for execution. It is an opinionated builder that defines
    47  // the step order required to build a complete graph as is used and expected
    48  // by Terraform.
    49  //
    50  // If you require a custom graph, you'll have to build it up manually
    51  // on your own by building a new GraphBuilder implementation.
    52  type BuiltinGraphBuilder struct {
    53  	// Root is the root module of the graph to build.
    54  	Root *module.Tree
    55  
    56  	// Diff is the diff. The proper module diffs will be looked up.
    57  	Diff *Diff
    58  
    59  	// State is the global state. The proper module states will be looked
    60  	// up by graph path.
    61  	State *State
    62  
    63  	// Providers is the list of providers supported.
    64  	Providers []string
    65  
    66  	// Provisioners is the list of provisioners supported.
    67  	Provisioners []string
    68  
    69  	// Targets is the user-specified list of resources to target.
    70  	Targets []string
    71  
    72  	// Destroy is set to true when we're in a `terraform destroy` or a
    73  	// `terraform plan -destroy`
    74  	Destroy bool
    75  }
    76  
    77  // Build builds the graph according to the steps returned by Steps.
    78  func (b *BuiltinGraphBuilder) Build(path []string) (*Graph, error) {
    79  	basic := &BasicGraphBuilder{
    80  		Steps: b.Steps(),
    81  	}
    82  
    83  	return basic.Build(path)
    84  }
    85  
    86  // Steps returns the ordered list of GraphTransformers that must be executed
    87  // to build a complete graph.
    88  func (b *BuiltinGraphBuilder) Steps() []GraphTransformer {
    89  	return []GraphTransformer{
    90  		// Create all our resources from the configuration and state
    91  		&ConfigTransformer{Module: b.Root},
    92  		&OrphanTransformer{
    93  			State:     b.State,
    94  			Module:    b.Root,
    95  			Targeting: (len(b.Targets) > 0),
    96  		},
    97  
    98  		// Provider-related transformations
    99  		&MissingProviderTransformer{Providers: b.Providers},
   100  		&ProviderTransformer{},
   101  		&PruneProviderTransformer{},
   102  		&DisableProviderTransformer{},
   103  
   104  		// Provisioner-related transformations
   105  		&MissingProvisionerTransformer{Provisioners: b.Provisioners},
   106  		&ProvisionerTransformer{},
   107  		&PruneProvisionerTransformer{},
   108  
   109  		// Run our vertex-level transforms
   110  		&VertexTransformer{
   111  			Transforms: []GraphVertexTransformer{
   112  				// Expand any statically expanded nodes, such as module graphs
   113  				&ExpandTransform{
   114  					Builder: b,
   115  				},
   116  			},
   117  		},
   118  
   119  		// Optionally reduces the graph to a user-specified list of targets and
   120  		// their dependencies.
   121  		&TargetsTransformer{Targets: b.Targets, Destroy: b.Destroy},
   122  
   123  		// Create the destruction nodes
   124  		&DestroyTransformer{},
   125  		&CreateBeforeDestroyTransformer{},
   126  		&PruneDestroyTransformer{Diff: b.Diff, State: b.State},
   127  
   128  		// Make sure we create one root
   129  		&RootTransformer{},
   130  
   131  		// Perform the transitive reduction to make our graph a bit
   132  		// more sane if possible (it usually is possible).
   133  		&TransitiveReductionTransformer{},
   134  	}
   135  }