terraform: destroy graph builder, -Xnew-destroy flag
This commit is contained in:
parent
bff4e31070
commit
db807f4b0f
|
@ -21,6 +21,10 @@ var (
|
||||||
// X_newApply will enable the new apply graph. This will be removed
|
// X_newApply will enable the new apply graph. This will be removed
|
||||||
// and be on by default in 0.8.0.
|
// and be on by default in 0.8.0.
|
||||||
X_newApply = false
|
X_newApply = false
|
||||||
|
|
||||||
|
// X_newDestroy will enable the new destroy graph. This will be removed
|
||||||
|
// and be on by default in 0.8.0.
|
||||||
|
X_newDestroy = false
|
||||||
)
|
)
|
||||||
|
|
||||||
// InputMode defines what sort of input will be asked for when Input
|
// InputMode defines what sort of input will be asked for when Input
|
||||||
|
@ -371,6 +375,8 @@ func (c *Context) Apply() (*State, error) {
|
||||||
// Copy our own state
|
// Copy our own state
|
||||||
c.state = c.state.DeepCopy()
|
c.state = c.state.DeepCopy()
|
||||||
|
|
||||||
|
newGraphEnabled := (c.destroy && X_newDestroy) || (!c.destroy && X_newApply)
|
||||||
|
|
||||||
// Build the original graph. This is before the new graph builders
|
// Build the original graph. This is before the new graph builders
|
||||||
// coming in 0.8. We do this for shadow graphing.
|
// coming in 0.8. We do this for shadow graphing.
|
||||||
oldGraph, err := c.Graph(&ContextGraphOpts{Validate: true})
|
oldGraph, err := c.Graph(&ContextGraphOpts{Validate: true})
|
||||||
|
@ -386,18 +392,28 @@ func (c *Context) Apply() (*State, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the new graph. We do this no matter what so we can shadow it.
|
// Build the new graph. We do this no matter what so we can shadow it.
|
||||||
newGraph, err := (&ApplyGraphBuilder{
|
var newGraph *Graph
|
||||||
Module: c.module,
|
if c.destroy {
|
||||||
Diff: c.diff,
|
newGraph, err = (&DestroyApplyGraphBuilder{
|
||||||
State: c.state,
|
Module: c.module,
|
||||||
Providers: c.components.ResourceProviders(),
|
Diff: c.diff,
|
||||||
Provisioners: c.components.ResourceProvisioners(),
|
State: c.state,
|
||||||
}).Build(RootModulePath)
|
Providers: c.providersList(),
|
||||||
if err != nil && !X_newApply {
|
}).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)
|
||||||
|
}
|
||||||
|
if err != nil && !newGraphEnabled {
|
||||||
// If we had an error graphing but we're not using this graph, just
|
// 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.
|
// set it to nil and record it as a shadow error.
|
||||||
c.shadowErr = multierror.Append(c.shadowErr, fmt.Errorf(
|
c.shadowErr = multierror.Append(c.shadowErr, fmt.Errorf(
|
||||||
"Error building new apply graph: %s", err))
|
"Error building new graph: %s", err))
|
||||||
|
|
||||||
newGraph = nil
|
newGraph = nil
|
||||||
err = nil
|
err = nil
|
||||||
|
@ -418,16 +434,11 @@ func (c *Context) Apply() (*State, error) {
|
||||||
//
|
//
|
||||||
real := oldGraph
|
real := oldGraph
|
||||||
shadow := newGraph
|
shadow := newGraph
|
||||||
if c.destroy {
|
if newGraphEnabled {
|
||||||
log.Printf("[WARN] terraform: real graph is original, shadow is nil")
|
log.Printf("[WARN] terraform: real graph is experiment, shadow is experiment")
|
||||||
shadow = nil
|
real = shadow
|
||||||
} else {
|
} else {
|
||||||
if X_newApply {
|
log.Printf("[WARN] terraform: real graph is original, shadow is experiment")
|
||||||
log.Printf("[WARN] terraform: real graph is Xnew-apply, shadow is Xnew-apply")
|
|
||||||
real = shadow
|
|
||||||
} else {
|
|
||||||
log.Printf("[WARN] terraform: real graph is original, shadow is Xnew-apply")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For now, always shadow with the real graph for verification. We don't
|
// For now, always shadow with the real graph for verification. We don't
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
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{},
|
||||||
|
&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
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ const fixtureDir = "./test-fixtures"
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
// Experimental features
|
// Experimental features
|
||||||
xNewApply := flag.Bool("Xnew-apply", false, "Experiment: new apply graph")
|
xNewApply := flag.Bool("Xnew-apply", false, "Experiment: new apply graph")
|
||||||
|
xNewDestroy := flag.Bool("Xnew-destroy", false, "Experiment: new destroy graph")
|
||||||
|
|
||||||
// Normal features
|
// Normal features
|
||||||
shadow := flag.Bool("shadow", true, "Enable shadow graph")
|
shadow := flag.Bool("shadow", true, "Enable shadow graph")
|
||||||
|
@ -32,6 +33,7 @@ func TestMain(m *testing.M) {
|
||||||
|
|
||||||
// Setup experimental features
|
// Setup experimental features
|
||||||
X_newApply = *xNewApply
|
X_newApply = *xNewApply
|
||||||
|
X_newDestroy = *xNewDestroy
|
||||||
|
|
||||||
if testing.Verbose() {
|
if testing.Verbose() {
|
||||||
// if we're verbose, use the logging requested by TF_LOG
|
// if we're verbose, use the logging requested by TF_LOG
|
||||||
|
|
Loading…
Reference in New Issue