core: fix deadlock w/ CBD + modules
fixes #1947 Root cause was a bad edge being made by the CBD transform going from the flattened destroy node to the unflattened create node, which was no longer in the graph. The destroy node therefore had a dependency that could never be satisfied, which locked up the walk.
This commit is contained in:
parent
725f66796b
commit
b0eafeb212
|
@ -139,6 +139,56 @@ func TestContext2Plan_moduleCycle(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestContext2Plan_moduleDeadlock(t *testing.T) {
|
||||
m := testModule(t, "plan-module-deadlock")
|
||||
p := testProvider("aws")
|
||||
p.DiffFn = testDiffFn
|
||||
timeout := make(chan bool, 1)
|
||||
done := make(chan bool, 1)
|
||||
go func() {
|
||||
time.Sleep(3 * time.Second)
|
||||
timeout <- true
|
||||
}()
|
||||
go func() {
|
||||
ctx := testContext2(t, &ContextOpts{
|
||||
Module: m,
|
||||
Providers: map[string]ResourceProviderFactory{
|
||||
"aws": testProviderFuncFixed(p),
|
||||
},
|
||||
})
|
||||
|
||||
plan, err := ctx.Plan()
|
||||
done <- true
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
actual := strings.TrimSpace(plan.String())
|
||||
expected := strings.TrimSpace(`
|
||||
DIFF:
|
||||
|
||||
module.child:
|
||||
CREATE: aws_instance.foo.0
|
||||
CREATE: aws_instance.foo.1
|
||||
CREATE: aws_instance.foo.2
|
||||
|
||||
STATE:
|
||||
|
||||
<no state>
|
||||
`)
|
||||
if actual != expected {
|
||||
t.Fatalf("expected:\n%sgot:\n%s", expected, actual)
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-timeout:
|
||||
t.Fatalf("timed out! probably deadlock")
|
||||
case <-done:
|
||||
// ok
|
||||
}
|
||||
}
|
||||
|
||||
func TestContext2Plan_moduleInput(t *testing.T) {
|
||||
m := testModule(t, "plan-module-input")
|
||||
p := testProvider("aws")
|
||||
|
|
|
@ -311,6 +311,7 @@ func (n *GraphNodeConfigResourceFlat) DestroyNode(mode GraphNodeDestroyMode) Gra
|
|||
return &graphNodeResourceDestroyFlat{
|
||||
graphNodeResourceDestroy: node,
|
||||
PathValue: n.PathValue,
|
||||
FlatCreateNode: n,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,6 +319,9 @@ type graphNodeResourceDestroyFlat struct {
|
|||
*graphNodeResourceDestroy
|
||||
|
||||
PathValue []string
|
||||
|
||||
// Needs to be able to properly yield back a flattened create node to prevent
|
||||
FlatCreateNode *GraphNodeConfigResourceFlat
|
||||
}
|
||||
|
||||
func (n *graphNodeResourceDestroyFlat) Name() string {
|
||||
|
@ -329,6 +333,10 @@ func (n *graphNodeResourceDestroyFlat) Path() []string {
|
|||
return n.PathValue
|
||||
}
|
||||
|
||||
func (n *graphNodeResourceDestroyFlat) CreateNode() dag.Vertex {
|
||||
return n.FlatCreateNode
|
||||
}
|
||||
|
||||
// graphNodeResourceDestroy represents the logical destruction of a
|
||||
// resource. This node doesn't mean it will be destroyed for sure, but
|
||||
// instead that if a destroy were to happen, it must happen at this point.
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
resource "aws_instance" "foo" {
|
||||
count = "${length("abc")}"
|
||||
lifecycle { create_before_destroy = true }
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
module "child" {
|
||||
source = "./child"
|
||||
}
|
Loading…
Reference in New Issue