2015-02-02 05:04:02 -06:00
|
|
|
package terraform
|
|
|
|
|
|
|
|
import (
|
2015-02-13 12:04:11 -06:00
|
|
|
"log"
|
|
|
|
|
2015-02-02 05:04:02 -06:00
|
|
|
"github.com/hashicorp/terraform/config/module"
|
|
|
|
)
|
|
|
|
|
|
|
|
// GraphBuilder is an interface that can be implemented and used with
|
|
|
|
// Terraform to build the graph that Terraform walks.
|
|
|
|
type GraphBuilder interface {
|
|
|
|
// Build builds the graph for the given module path. It is up to
|
|
|
|
// the interface implementation whether this build should expand
|
|
|
|
// the graph or not.
|
|
|
|
Build(path []string) (*Graph, error)
|
|
|
|
}
|
|
|
|
|
2015-02-07 18:19:08 -06:00
|
|
|
// BasicGraphBuilder is a GraphBuilder that builds a graph out of a
|
|
|
|
// series of transforms and validates the graph is a valid structure.
|
|
|
|
type BasicGraphBuilder struct {
|
|
|
|
Steps []GraphTransformer
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *BasicGraphBuilder) Build(path []string) (*Graph, error) {
|
|
|
|
g := &Graph{Path: path}
|
|
|
|
for _, step := range b.Steps {
|
|
|
|
if err := step.Transform(g); err != nil {
|
|
|
|
return g, err
|
|
|
|
}
|
2015-02-13 14:05:34 -06:00
|
|
|
|
2015-03-02 10:41:09 -06:00
|
|
|
log.Printf(
|
|
|
|
"[TRACE] Graph after step %T:\n\n%s",
|
|
|
|
step, g.String())
|
2015-02-07 18:19:08 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Validate the graph structure
|
|
|
|
if err := g.Validate(); err != nil {
|
2015-02-13 14:05:34 -06:00
|
|
|
log.Printf("[ERROR] Graph validation failed. Graph:\n\n%s", g.String())
|
2015-02-07 18:19:08 -06:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return g, nil
|
|
|
|
}
|
|
|
|
|
2015-02-02 05:04:02 -06:00
|
|
|
// BuiltinGraphBuilder is responsible for building the complete graph that
|
|
|
|
// Terraform uses for execution. It is an opinionated builder that defines
|
|
|
|
// the step order required to build a complete graph as is used and expected
|
|
|
|
// by Terraform.
|
|
|
|
//
|
|
|
|
// If you require a custom graph, you'll have to build it up manually
|
|
|
|
// on your own by building a new GraphBuilder implementation.
|
|
|
|
type BuiltinGraphBuilder struct {
|
|
|
|
// Root is the root module of the graph to build.
|
|
|
|
Root *module.Tree
|
|
|
|
|
2015-02-13 14:05:34 -06:00
|
|
|
// Diff is the diff. The proper module diffs will be looked up.
|
|
|
|
Diff *Diff
|
|
|
|
|
2015-02-02 05:04:02 -06:00
|
|
|
// State is the global state. The proper module states will be looked
|
|
|
|
// up by graph path.
|
|
|
|
State *State
|
|
|
|
|
|
|
|
// Providers is the list of providers supported.
|
|
|
|
Providers []string
|
2015-02-09 13:15:54 -06:00
|
|
|
|
|
|
|
// Provisioners is the list of provisioners supported.
|
|
|
|
Provisioners []string
|
2015-03-24 11:18:15 -05:00
|
|
|
|
|
|
|
// Targets is the user-specified list of resources to target.
|
|
|
|
Targets []string
|
|
|
|
|
|
|
|
// Destroy is set to true when we're in a `terraform destroy` or a
|
|
|
|
// `terraform plan -destroy`
|
|
|
|
Destroy bool
|
2015-02-02 05:04:02 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Build builds the graph according to the steps returned by Steps.
|
|
|
|
func (b *BuiltinGraphBuilder) Build(path []string) (*Graph, error) {
|
2015-02-07 18:19:08 -06:00
|
|
|
basic := &BasicGraphBuilder{
|
|
|
|
Steps: b.Steps(),
|
2015-02-02 05:04:02 -06:00
|
|
|
}
|
|
|
|
|
2015-02-07 18:19:08 -06:00
|
|
|
return basic.Build(path)
|
2015-02-02 05:04:02 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Steps returns the ordered list of GraphTransformers that must be executed
|
|
|
|
// to build a complete graph.
|
|
|
|
func (b *BuiltinGraphBuilder) Steps() []GraphTransformer {
|
|
|
|
return []GraphTransformer{
|
2015-02-09 12:14:09 -06:00
|
|
|
// Create all our resources from the configuration and state
|
2015-02-02 05:04:02 -06:00
|
|
|
&ConfigTransformer{Module: b.Root},
|
2015-03-30 19:02:36 -05:00
|
|
|
&OrphanTransformer{
|
|
|
|
State: b.State,
|
|
|
|
Module: b.Root,
|
|
|
|
Targeting: (len(b.Targets) > 0),
|
|
|
|
},
|
2015-02-09 12:14:09 -06:00
|
|
|
|
|
|
|
// Provider-related transformations
|
2015-02-02 05:04:02 -06:00
|
|
|
&MissingProviderTransformer{Providers: b.Providers},
|
|
|
|
&ProviderTransformer{},
|
|
|
|
&PruneProviderTransformer{},
|
2015-04-08 23:14:19 -05:00
|
|
|
&DisableProviderTransformer{},
|
2015-02-09 12:14:09 -06:00
|
|
|
|
|
|
|
// Provisioner-related transformations
|
2015-02-09 13:15:54 -06:00
|
|
|
&MissingProvisionerTransformer{Provisioners: b.Provisioners},
|
|
|
|
&ProvisionerTransformer{},
|
|
|
|
&PruneProvisionerTransformer{},
|
2015-02-09 12:14:09 -06:00
|
|
|
|
|
|
|
// Run our vertex-level transforms
|
2015-02-07 18:29:04 -06:00
|
|
|
&VertexTransformer{
|
|
|
|
Transforms: []GraphVertexTransformer{
|
2015-02-09 12:14:09 -06:00
|
|
|
// Expand any statically expanded nodes, such as module graphs
|
2015-02-07 18:29:04 -06:00
|
|
|
&ExpandTransform{
|
|
|
|
Builder: b,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-02-09 12:14:09 -06:00
|
|
|
|
2015-03-24 11:18:15 -05:00
|
|
|
// Optionally reduces the graph to a user-specified list of targets and
|
|
|
|
// their dependencies.
|
|
|
|
&TargetsTransformer{Targets: b.Targets, Destroy: b.Destroy},
|
|
|
|
|
2015-02-12 12:54:28 -06:00
|
|
|
// Create the destruction nodes
|
|
|
|
&DestroyTransformer{},
|
2015-02-13 17:57:37 -06:00
|
|
|
&CreateBeforeDestroyTransformer{},
|
2015-02-16 14:20:53 -06:00
|
|
|
&PruneDestroyTransformer{Diff: b.Diff, State: b.State},
|
2015-02-12 12:54:28 -06:00
|
|
|
|
2015-02-09 12:14:09 -06:00
|
|
|
// Make sure we create one root
|
2015-02-04 19:02:18 -06:00
|
|
|
&RootTransformer{},
|
2015-02-27 21:23:20 -06:00
|
|
|
|
|
|
|
// Perform the transitive reduction to make our graph a bit
|
|
|
|
// more sane if possible (it usually is possible).
|
|
|
|
&TransitiveReductionTransformer{},
|
2015-02-02 05:04:02 -06:00
|
|
|
}
|
|
|
|
}
|