ensure destroy edges from data sources

Data resource dependencies are not stored in the state, so we need to
take the latest dependency set to use for any direct connections to
destroy nodes.
This commit is contained in:
James Bardin 2022-11-08 10:21:35 -05:00
parent be5984d664
commit ebd5a17b17
2 changed files with 56 additions and 2 deletions

View File

@ -96,15 +96,21 @@ func (n *NodeAbstractResourceInstance) References() []*addrs.Reference {
return nil
}
// StateDependencies returns the dependencies saved in the state.
// StateDependencies returns the dependencies which will be saved in the state
// for managed resources, or the most current dependencies for data resources.
func (n *NodeAbstractResourceInstance) StateDependencies() []addrs.ConfigResource {
// Managed resources prefer the stored dependencies, to avoid possible
// conflicts in ordering when refactoring configuration.
if s := n.instanceState; s != nil {
if s.Current != nil {
return s.Current.Dependencies
}
}
return nil
// If there are no stored dependencies, this is either a newly created
// managed resource, or a data source, and we can use the most recently
// calculated dependencies.
return n.Dependencies
}
// GraphNodeProviderConsumer

View File

@ -509,6 +509,54 @@ test_object.C (destroy)`)
}
}
func TestDestroyEdgeTransformer_dataDependsOn(t *testing.T) {
g := Graph{Path: addrs.RootModuleInstance}
addrA := mustResourceInstanceAddr("test_object.A")
instA := NewNodeAbstractResourceInstance(addrA)
a := &NodeDestroyResourceInstance{NodeAbstractResourceInstance: instA}
g.Add(a)
// B here represents a data sources, which is effectively an update during
// apply, but won't have dependencies stored in the state.
addrB := mustResourceInstanceAddr("test_object.B")
instB := NewNodeAbstractResourceInstance(addrB)
instB.Dependencies = append(instB.Dependencies, addrA.ConfigResource())
b := &NodeApplyableResourceInstance{NodeAbstractResourceInstance: instB}
g.Add(b)
state := states.NewState()
root := state.EnsureModule(addrs.RootModuleInstance)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_object.A").Resource,
&states.ResourceInstanceObjectSrc{
Status: states.ObjectReady,
AttrsJSON: []byte(`{"id":"A"}`),
},
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
)
if err := (&AttachStateTransformer{State: state}).Transform(&g); err != nil {
t.Fatal(err)
}
tf := &DestroyEdgeTransformer{}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(`
test_object.A (destroy)
test_object.B
test_object.A (destroy)
`)
if actual != expected {
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
}
}
func testDestroyNode(addrString string) GraphNodeDestroyer {
instAddr := mustResourceInstanceAddr(addrString)
inst := NewNodeAbstractResourceInstance(instAddr)