terraform: destroy edges should never point to self

Fixes #9920

This was an issue caught with the shadow graph. Self references in
provisioners were causing a self-edge on destroy apply graphs.

We need to explicitly check that we're not creating an edge to ourself.
This is also how the reference transformer works.
This commit is contained in:
Mitchell Hashimoto 2016-11-08 12:27:33 -08:00
parent 8eb4678972
commit fb29b6a2dc
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
5 changed files with 106 additions and 1 deletions

View File

@ -3123,6 +3123,76 @@ func TestContext2Apply_provisionerMultiSelfRefCount(t *testing.T) {
}
}
func TestContext2Apply_provisionerExplicitSelfRef(t *testing.T) {
m := testModule(t, "apply-provisioner-explicit-self-ref")
p := testProvider("aws")
pr := testProvisioner()
p.ApplyFn = testApplyFn
p.DiffFn = testDiffFn
pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error {
val, ok := c.Config["command"]
if !ok || val != "bar" {
t.Fatalf("bad value for command: %v %#v", val, c)
}
return nil
}
var state *State
{
ctx := testContext2(t, &ContextOpts{
Module: m,
Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p),
},
Provisioners: map[string]ResourceProvisionerFactory{
"shell": testProvisionerFuncFixed(pr),
},
})
_, err := ctx.Plan()
if err != nil {
t.Fatalf("err: %s", err)
}
state, err = ctx.Apply()
if err != nil {
t.Fatalf("err: %s", err)
}
// Verify apply was invoked
if !pr.ApplyCalled {
t.Fatalf("provisioner not invoked")
}
}
{
ctx := testContext2(t, &ContextOpts{
Module: m,
Destroy: true,
State: state,
Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p),
},
Provisioners: map[string]ResourceProvisionerFactory{
"shell": testProvisionerFuncFixed(pr),
},
})
_, err := ctx.Plan()
if err != nil {
t.Fatalf("err: %s", err)
}
state, err = ctx.Apply()
if err != nil {
t.Fatalf("err: %s", err)
}
checkStateString(t, state, `<no state>`)
}
}
// Provisioner should NOT run on a diff, only create
func TestContext2Apply_Provisioner_Diff(t *testing.T) {
m := testModule(t, "apply-provisioner-diff")

View File

@ -0,0 +1,7 @@
resource "aws_instance" "foo" {
foo = "bar"
provisioner "shell" {
command = "${aws_instance.foo.foo}"
}
}

View File

@ -0,0 +1,5 @@
resource "test" "A" {
provisioner "foo" {
command = "${test.A.id}"
}
}

View File

@ -182,7 +182,9 @@ func (t *DestroyEdgeTransformer) Transform(g *Graph) error {
// names "a_d" and "b_d" to reference our example.
for _, a_d := range dns {
for _, b_d := range depDestroyers {
g.Connect(dag.BasicEdge(b_d, a_d))
if b_d != a_d {
g.Connect(dag.BasicEdge(b_d, a_d))
}
}
}
}

View File

@ -61,6 +61,23 @@ func TestDestroyEdgeTransformer_multi(t *testing.T) {
}
}
func TestDestroyEdgeTransformer_selfRef(t *testing.T) {
g := Graph{Path: RootModulePath}
g.Add(&graphNodeDestroyerTest{AddrString: "test.A"})
tf := &DestroyEdgeTransformer{
Module: testModule(t, "transform-destroy-edge-self-ref"),
}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(testTransformDestroyEdgeSelfRefStr)
if actual != expected {
t.Fatalf("bad:\n\n%s", actual)
}
}
type graphNodeCreatorTest struct {
AddrString string
}
@ -112,3 +129,7 @@ test.B (destroy)
test.C (destroy)
test.C (destroy)
`
const testTransformDestroyEdgeSelfRefStr = `
test.A (destroy)
`