terraform: unify destroy/apply graph builders

They're so similar we unify them, they only change in a select few
places. This is very similar to the old graph but is still much simpler.
This commit is contained in:
Mitchell Hashimoto 2016-10-20 23:22:33 -07:00
parent 1523504645
commit 5a8ec482a2
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
5 changed files with 57 additions and 130 deletions

View File

@ -392,23 +392,14 @@ func (c *Context) Apply() (*State, error) {
}
// Build the new graph. We do this no matter what so we can shadow it.
var newGraph *Graph
if c.destroy {
newGraph, err = (&DestroyApplyGraphBuilder{
Module: c.module,
Diff: c.diff,
State: c.state,
Providers: c.components.ResourceProviders(),
}).Build(RootModulePath)
} else {
newGraph, err = (&ApplyGraphBuilder{
Module: c.module,
Diff: c.diff,
State: c.state,
Providers: c.components.ResourceProviders(),
Provisioners: c.components.ResourceProvisioners(),
}).Build(RootModulePath)
}
newGraph, err := (&ApplyGraphBuilder{
Module: c.module,
Diff: c.diff,
State: c.state,
Providers: c.components.ResourceProviders(),
Provisioners: c.components.ResourceProvisioners(),
Destroy: c.destroy,
}).Build(RootModulePath)
if err != nil && !newGraphEnabled {
// If we had an error graphing but we're not using this graph, just
// set it to nil and record it as a shadow error.

View File

@ -26,6 +26,10 @@ type BasicGraphBuilder struct {
func (b *BasicGraphBuilder) Build(path []string) (*Graph, error) {
g := &Graph{Path: path}
for _, step := range b.Steps {
if step == nil {
continue
}
if err := step.Transform(g); err != nil {
return g, err
}

View File

@ -30,6 +30,9 @@ type ApplyGraphBuilder struct {
// DisableReduce, if true, will not reduce the graph. Great for testing.
DisableReduce bool
// Destroy, if true, represents a pure destroy operation
Destroy bool
}
// See GraphBuilder
@ -77,7 +80,10 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer {
// Destruction ordering
&DestroyEdgeTransformer{Module: b.Module, State: b.State},
&CBDEdgeTransformer{Module: b.Module, State: b.State},
GraphTransformIf(
func() bool { return !b.Destroy },
&CBDEdgeTransformer{Module: b.Module, State: b.State},
),
// Create all the providers
&MissingProviderTransformer{Providers: b.Providers, Factory: providerFactory},
@ -87,8 +93,13 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer {
&AttachProviderConfigTransformer{Module: b.Module},
// Provisioner-related transformations
&MissingProvisionerTransformer{Provisioners: b.Provisioners},
&ProvisionerTransformer{},
GraphTransformIf(
func() bool { return !b.Destroy },
GraphTransformMulti(
&MissingProvisionerTransformer{Provisioners: b.Provisioners},
&ProvisionerTransformer{},
),
),
// Add root variables
&RootVariableTransformer{Module: b.Module},

View File

@ -1,110 +0,0 @@
package terraform
import (
"github.com/hashicorp/terraform/config/module"
"github.com/hashicorp/terraform/dag"
)
// DestroyApplyGraphBuilder implements GraphBuilder and is responsible for
// applying a pure-destroy plan.
//
// This graph builder is very similar to the ApplyGraphBuilder but
// is slightly simpler.
type DestroyApplyGraphBuilder struct {
// Module is the root module for the graph to build.
Module *module.Tree
// Diff is the diff to apply.
Diff *Diff
// State is the current state
State *State
// Providers is the list of providers supported.
Providers []string
// DisableReduce, if true, will not reduce the graph. Great for testing.
DisableReduce bool
}
// See GraphBuilder
func (b *DestroyApplyGraphBuilder) Build(path []string) (*Graph, error) {
return (&BasicGraphBuilder{
Steps: b.Steps(),
Validate: true,
}).Build(path)
}
// See GraphBuilder
func (b *DestroyApplyGraphBuilder) Steps() []GraphTransformer {
// Custom factory for creating providers.
providerFactory := func(name string, path []string) GraphNodeProvider {
return &NodeApplyableProvider{
NameValue: name,
PathValue: path,
}
}
concreteResource := func(a *NodeAbstractResource) dag.Vertex {
return &NodeApplyableResource{
NodeAbstractResource: a,
}
}
steps := []GraphTransformer{
// Creates all the nodes represented in the diff.
&DiffTransformer{
Concrete: concreteResource,
Diff: b.Diff,
Module: b.Module,
State: b.State,
},
// Create orphan output nodes
&OrphanOutputTransformer{Module: b.Module, State: b.State},
// Attach the configuration to any resources
&AttachResourceConfigTransformer{Module: b.Module},
// Attach the state
&AttachStateTransformer{State: b.State},
// Destruction ordering. NOTE: For destroys, we don't need to
// do any CBD stuff, so that is explicitly not here.
&DestroyEdgeTransformer{Module: b.Module, State: b.State},
// Create all the providers
&MissingProviderTransformer{Providers: b.Providers, Factory: providerFactory},
&ProviderTransformer{},
&DisableProviderTransformer{},
&ParentProviderTransformer{},
&AttachProviderConfigTransformer{Module: b.Module},
// Add root variables
&RootVariableTransformer{Module: b.Module},
// Add module variables
&ModuleVariableTransformer{Module: b.Module},
// Add the outputs
&OutputTransformer{Module: b.Module},
// Connect references so ordering is correct
&ReferenceTransformer{},
// Add the node to fix the state count boundaries
&CountBoundaryTransformer{},
// Single root
&RootTransformer{},
}
if !b.DisableReduce {
// Perform the transitive reduction to make our graph a bit
// more sane if possible (it usually is possible).
steps = append(steps, &TransitiveReductionTransformer{})
}
return steps
}

View File

@ -19,3 +19,34 @@ type GraphTransformer interface {
type GraphVertexTransformer interface {
Transform(dag.Vertex) (dag.Vertex, error)
}
// GraphTransformIf is a helper function that conditionally returns a
// GraphTransformer given. This is useful for calling inline a sequence
// of transforms without having to split it up into multiple append() calls.
func GraphTransformIf(f func() bool, then GraphTransformer) GraphTransformer {
if f() {
return then
}
return nil
}
type graphTransformerMulti struct {
Transforms []GraphTransformer
}
func (t *graphTransformerMulti) Transform(g *Graph) error {
for _, t := range t.Transforms {
if err := t.Transform(g); err != nil {
return err
}
}
return nil
}
// GraphTransformMulti combines multiple graph transformers into a single
// GraphTransformer that runs all the individual graph transformers.
func GraphTransformMulti(ts ...GraphTransformer) GraphTransformer {
return &graphTransformerMulti{Transforms: ts}
}