diff --git a/internal/terraform/context_apply_action_test.go b/internal/terraform/context_apply_action_test.go index 630d467275..7f35ac0cd4 100644 --- a/internal/terraform/context_apply_action_test.go +++ b/internal/terraform/context_apply_action_test.go @@ -2857,6 +2857,30 @@ func TestContextApply_actions_resource_action_ordering(t *testing.T) { "InvokeAction action_example - cty.ObjectVal(map[string]cty.Value{\"attr\":cty.StringVal(\"hello\")})", }, }, + "resource dependencies in before_create action": { + module: map[string]string{ + "main.tf": ` + action "action_example" "hello" {} + resource "test_object" "dep" { + name = "dep" + } + resource "test_object" "a" { + depends_on = [test_object.dep] + name = "a" + lifecycle { + action_trigger { + events = [before_create] + actions = [action.action_example.hello] + } + } + }`, + }, + expectedOrder: []string{ + "ApplyResourceChangeFn test_object - cty.ObjectVal(map[string]cty.Value{\"name\":cty.StringVal(\"dep\")})", + "InvokeAction action_example - cty.NilVal", + "ApplyResourceChangeFn test_object - cty.ObjectVal(map[string]cty.Value{\"name\":cty.StringVal(\"a\")})", + }, + }, } { t.Run(name, func(t *testing.T) { m := testModuleInline(t, tc.module) diff --git a/internal/terraform/graph_builder_apply.go b/internal/terraform/graph_builder_apply.go index 7ea5a6a3a6..9a2ab3fa0f 100644 --- a/internal/terraform/graph_builder_apply.go +++ b/internal/terraform/graph_builder_apply.go @@ -167,11 +167,12 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer { Operation: b.Operation, ActionTargets: b.ActionTargets, - ConcreteActionTriggerNodeFunc: func(node *nodeAbstractActionTriggerExpand, timing RelativeActionTiming) dag.Vertex { + ConcreteActionTriggerNodeFunc: func(node *nodeAbstractActionTriggerExpand, timing RelativeActionTiming, refs []*addrs.Reference) dag.Vertex { return &nodeActionTriggerApplyExpand{ nodeAbstractActionTriggerExpand: node, - relativeTiming: timing, + relativeTiming: timing, + inheritedReferences: refs, } }, }, diff --git a/internal/terraform/graph_builder_plan.go b/internal/terraform/graph_builder_plan.go index 3ef6ae3e18..c5218bf190 100644 --- a/internal/terraform/graph_builder_plan.go +++ b/internal/terraform/graph_builder_plan.go @@ -178,7 +178,7 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer { ActionTargets: b.ActionTargets, queryPlanMode: b.queryPlan, - ConcreteActionTriggerNodeFunc: func(node *nodeAbstractActionTriggerExpand, _ RelativeActionTiming) dag.Vertex { + ConcreteActionTriggerNodeFunc: func(node *nodeAbstractActionTriggerExpand, _ RelativeActionTiming, _ []*addrs.Reference) dag.Vertex { return &nodeActionTriggerPlanExpand{ nodeAbstractActionTriggerExpand: node, } diff --git a/internal/terraform/node_action_trigger_abstract.go b/internal/terraform/node_action_trigger_abstract.go index 60aceb955e..aede53b3fe 100644 --- a/internal/terraform/node_action_trigger_abstract.go +++ b/internal/terraform/node_action_trigger_abstract.go @@ -23,7 +23,7 @@ const ( // ConcreteActionTriggerNodeFunc is a callback type used to convert an // abstract action trigger to a concrete one of some type. -type ConcreteActionTriggerNodeFunc func(*nodeAbstractActionTriggerExpand, RelativeActionTiming) dag.Vertex +type ConcreteActionTriggerNodeFunc func(*nodeAbstractActionTriggerExpand, RelativeActionTiming, []*addrs.Reference) dag.Vertex type nodeAbstractActionTriggerExpand struct { Addr addrs.ConfigAction diff --git a/internal/terraform/node_action_trigger_apply.go b/internal/terraform/node_action_trigger_apply.go index 2700611f5d..39c6d2e355 100644 --- a/internal/terraform/node_action_trigger_apply.go +++ b/internal/terraform/node_action_trigger_apply.go @@ -18,6 +18,7 @@ type nodeActionTriggerApplyExpand struct { actionInvocationInstances []*plans.ActionInvocationInstanceSrc relativeTiming RelativeActionTiming + inheritedReferences []*addrs.Reference } var ( @@ -74,6 +75,7 @@ func (n *nodeActionTriggerApplyExpand) References() []*addrs.Reference { refs = append(refs, &addrs.Reference{ Subject: n.Addr.Action, }) + refs = append(refs, n.inheritedReferences...) if n.lifecycleActionTrigger != nil { conditionRefs, _ := langrefs.ReferencesInExpr(addrs.ParseRef, n.lifecycleActionTrigger.conditionExpr) diff --git a/internal/terraform/node_resource_abstract.go b/internal/terraform/node_resource_abstract.go index f4787cb30e..ee711e11a6 100644 --- a/internal/terraform/node_resource_abstract.go +++ b/internal/terraform/node_resource_abstract.go @@ -28,6 +28,10 @@ type GraphNodeConfigResource interface { ResourceAddr() addrs.ConfigResource } +type GraphNodeDependsOn interface { + DependsOn() []*addrs.Reference +} + // ConcreteResourceInstanceNodeFunc is a callback type used to convert an // abstract resource instance to a concrete one of some type. type ConcreteResourceInstanceNodeFunc func(*NodeAbstractResourceInstance) dag.Vertex @@ -109,6 +113,7 @@ var ( _ graphNodeAttachDataResourceDependsOn = (*NodeAbstractResource)(nil) _ dag.GraphNodeDotter = (*NodeAbstractResource)(nil) _ GraphNodeDestroyerCBD = (*NodeAbstractResource)(nil) + _ GraphNodeDependsOn = (*NodeAbstractResource)(nil) ) // NewNodeAbstractResource creates an abstract resource graph node for diff --git a/internal/terraform/node_resource_apply.go b/internal/terraform/node_resource_apply.go index e587ecc1a3..fbb5649ef5 100644 --- a/internal/terraform/node_resource_apply.go +++ b/internal/terraform/node_resource_apply.go @@ -4,6 +4,9 @@ package terraform import ( + "fmt" + "runtime/debug" + "github.com/hashicorp/terraform/internal/addrs" "github.com/hashicorp/terraform/internal/dag" "github.com/hashicorp/terraform/internal/tfdiags" @@ -30,6 +33,11 @@ var ( func (n *nodeExpandApplyableResource) References() []*addrs.Reference { refs := n.NodeAbstractResource.References() + fmt.Printf("ExpandApplyableResource %s references: %v\n", n.Name(), refs) + fmt.Println("===== refs ======") + debug.PrintStack() + fmt.Println("===== refs (END) ======") + return refs // The expand node needs to connect to the individual resource instances it // references, but cannot refer to it's own instances without causing @@ -39,7 +47,8 @@ func (n *nodeExpandApplyableResource) References() []*addrs.Reference { // filter them out for all resource node types, because the only method we // have for catching certain invalid configurations are the cycles that // result from these inter-instance references. - return filterSelfRefs(n.Addr.Resource, refs) + // return filterSelfRefs(n.Addr.Resource, refs) + return refs } func (n *nodeExpandApplyableResource) Name() string { diff --git a/internal/terraform/transform_action_trigger_config.go b/internal/terraform/transform_action_trigger_config.go index 42ed56bc78..f652ef3208 100644 --- a/internal/terraform/transform_action_trigger_config.go +++ b/internal/terraform/transform_action_trigger_config.go @@ -141,10 +141,25 @@ func (t *ActionTriggerConfigTransformer) transformSingle(g *Graph, config *confi }, } + // Before_* actions during apply need to be aware of any dependent references to resources + additionalReferences := []*addrs.Reference{} + if t.Operation == walkApply { + for _, rn := range resourceNode { + if gr, ok := rn.(*nodeExpandApplyableResource); ok { + fmt.Printf("\n\n Resource Node --> %#v\n", gr.Addr.String()) + asd := gr.References() + fmt.Printf("\n\t asd --> %#v\n", asd) + + additionalReferences = append(additionalReferences, asd...) + } + } + } + fmt.Printf("\n\n additionalReferences --> %#v\n", additionalReferences) + // If CreateNodesAsAfter is set we want all nodes to run after the resource // If not we want expansion nodes only to exist if they are being used if !createNodesAsAfter && containsBeforeEvent { - nat := t.ConcreteActionTriggerNodeFunc(abstract, RelativeActionTimingBefore) + nat := t.ConcreteActionTriggerNodeFunc(abstract, RelativeActionTimingBefore, additionalReferences) g.Add(nat) // We want to run before the resource nodes @@ -165,7 +180,7 @@ func (t *ActionTriggerConfigTransformer) transformSingle(g *Graph, config *confi } if createNodesAsAfter || containsAfterEvent { - nat := t.ConcreteActionTriggerNodeFunc(abstract, RelativeActionTimingAfter) + nat := t.ConcreteActionTriggerNodeFunc(abstract, RelativeActionTimingAfter, additionalReferences) g.Add(nat) // We want to run after the resource nodes diff --git a/internal/terraform/validate_selfref.go b/internal/terraform/validate_selfref.go index fc22028929..e524d92e54 100644 --- a/internal/terraform/validate_selfref.go +++ b/internal/terraform/validate_selfref.go @@ -144,6 +144,8 @@ func filterSelfRefs(self addrs.Resource, refs []*addrs.Reference) []*addrs.Refer for i := 0; i < len(refs); i++ { ref := refs[i] + fmt.Printf("\n\t ref --> %#v\n", ref) + var subject addrs.Resource switch subj := ref.Subject.(type) { case addrs.Resource: @@ -151,10 +153,12 @@ func filterSelfRefs(self addrs.Resource, refs []*addrs.Reference) []*addrs.Refer case addrs.ResourceInstance: subject = subj.ContainingResource() default: + fmt.Println("continueing...") continue } if self.Equal(subject) { + fmt.Println("eqlau") tail := len(refs) - 1 refs[i], refs[tail] = refs[tail], refs[i]