terraform: put destroy nodes into the graph
This commit is contained in:
parent
4caab6870b
commit
d7dc0291f5
|
@ -95,6 +95,9 @@ func (b *BuiltinGraphBuilder) Steps() []GraphTransformer {
|
|||
},
|
||||
},
|
||||
|
||||
// Create the destruction nodes
|
||||
&DestroyTransformer{},
|
||||
|
||||
// Make sure we create one root
|
||||
&RootTransformer{},
|
||||
}
|
||||
|
|
|
@ -106,8 +106,12 @@ const testBasicGraphBuilderStr = `
|
|||
|
||||
const testBuiltinGraphBuilderBasicStr = `
|
||||
aws_instance.db
|
||||
aws_instance.db (destroy)
|
||||
aws_instance.db (destroy)
|
||||
provider.aws
|
||||
aws_instance.web
|
||||
aws_instance.web (destroy)
|
||||
aws_instance.web (destroy)
|
||||
aws_instance.db
|
||||
provider.aws
|
||||
provider.aws
|
||||
|
@ -115,10 +119,14 @@ provider.aws
|
|||
|
||||
const testBuiltinGraphBuilderModuleStr = `
|
||||
aws_instance.web
|
||||
aws_instance.web (destroy)
|
||||
aws_instance.web (destroy)
|
||||
aws_security_group.firewall
|
||||
module.consul (expanded)
|
||||
provider.aws
|
||||
aws_security_group.firewall
|
||||
aws_security_group.firewall (destroy)
|
||||
aws_security_group.firewall (destroy)
|
||||
provider.aws
|
||||
module.consul (expanded)
|
||||
aws_security_group.firewall
|
||||
|
|
|
@ -243,6 +243,21 @@ func (n *GraphNodeConfigResource) ProvisionedBy() []string {
|
|||
return result
|
||||
}
|
||||
|
||||
// GraphNodeDestroyable
|
||||
func (n *GraphNodeConfigResource) DestroyNode() dag.Vertex {
|
||||
return &GraphNodeConfigResourceDestroy{Resource: n.Resource}
|
||||
}
|
||||
|
||||
// GraphNodeConfigResourceDestroy represents the logical destroy step for
|
||||
// a resource.
|
||||
type GraphNodeConfigResourceDestroy struct {
|
||||
Resource *config.Resource
|
||||
}
|
||||
|
||||
func (n *GraphNodeConfigResourceDestroy) Name() string {
|
||||
return fmt.Sprintf("%s (destroy)", n.Resource.Id())
|
||||
}
|
||||
|
||||
// graphNodeModuleExpanded represents a module where the graph has
|
||||
// been expanded. It stores the graph of the module as well as a reference
|
||||
// to the map of variables.
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
resource "aws_instance" "foo" {}
|
||||
|
||||
resource "aws_instance" "bar" {
|
||||
value = "${aws_instance.foo.value}"
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package terraform
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/dag"
|
||||
)
|
||||
|
||||
// GraphNodeDestroyable is the interface that nodes that can be destroyed
|
||||
// must implement. This is used to automatically handle the creation of
|
||||
// destroy nodes in the graph and the dependency ordering of those destroys.
|
||||
type GraphNodeDestroyable interface {
|
||||
// DestroyNode returns the node used for the destroy. This vertex
|
||||
// should not be in the graph yet.
|
||||
DestroyNode() dag.Vertex
|
||||
}
|
||||
|
||||
// DestroyTransformer is a GraphTransformer that creates the destruction
|
||||
// nodes for things that _might_ be destroyed.
|
||||
type DestroyTransformer struct{}
|
||||
|
||||
func (t *DestroyTransformer) Transform(g *Graph) error {
|
||||
for _, v := range g.Vertices() {
|
||||
// If it is not a destroyable, we don't care
|
||||
dn, ok := v.(GraphNodeDestroyable)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// Grab the destroy side of the node and connect it through
|
||||
n := dn.DestroyNode()
|
||||
if n == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Add it to the graph
|
||||
g.Add(n)
|
||||
|
||||
// Inherit all the edges from the old node
|
||||
downEdges := g.DownEdges(v).List()
|
||||
for _, edgeRaw := range downEdges {
|
||||
g.Connect(dag.BasicEdge(n, edgeRaw.(dag.Vertex)))
|
||||
}
|
||||
|
||||
// Remove all the edges from the old now
|
||||
for _, edgeRaw := range downEdges {
|
||||
g.RemoveEdge(dag.BasicEdge(v, edgeRaw.(dag.Vertex)))
|
||||
}
|
||||
|
||||
// Add a new edge to connect the node to be created to
|
||||
// the destroy node.
|
||||
g.Connect(dag.BasicEdge(v, n))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package terraform
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDestroyTransformer(t *testing.T) {
|
||||
mod := testModule(t, "transform-destroy-basic")
|
||||
|
||||
g := Graph{Path: RootModulePath}
|
||||
{
|
||||
tf := &ConfigTransformer{Module: mod}
|
||||
if err := tf.Transform(&g); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
tf := &DestroyTransformer{}
|
||||
if err := tf.Transform(&g); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
actual := strings.TrimSpace(g.String())
|
||||
expected := strings.TrimSpace(testTransformDestroyBasicStr)
|
||||
if actual != expected {
|
||||
t.Fatalf("bad:\n\n%s", actual)
|
||||
}
|
||||
}
|
||||
|
||||
const testTransformDestroyBasicStr = `
|
||||
aws_instance.bar
|
||||
aws_instance.bar (destroy)
|
||||
aws_instance.bar (destroy)
|
||||
aws_instance.foo
|
||||
aws_instance.foo
|
||||
aws_instance.foo (destroy)
|
||||
aws_instance.foo (destroy)
|
||||
`
|
Loading…
Reference in New Issue