diff --git a/internal/terraform/graph_builder_plan.go b/internal/terraform/graph_builder_plan.go index af0a82a021..bae28db5bd 100644 --- a/internal/terraform/graph_builder_plan.go +++ b/internal/terraform/graph_builder_plan.go @@ -170,6 +170,12 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer { Operation: b.Operation, ActionTargets: b.ActionTargets, queryPlanMode: b.queryPlan, + + ConcreteActionTriggerNodeFunc: func(node *nodeAbstractActionTriggerExpand) dag.Vertex { + return &nodeActionTriggerPlanExpand{ + nodeAbstractActionTriggerExpand: node, + } + }, }, &ActionInvokeTransformer{ diff --git a/internal/terraform/node_action_trigger_abstract.go b/internal/terraform/node_action_trigger_abstract.go new file mode 100644 index 0000000000..387151ba2d --- /dev/null +++ b/internal/terraform/node_action_trigger_abstract.go @@ -0,0 +1,99 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package terraform + +import ( + "fmt" + + "github.com/hashicorp/hcl/v2" + + "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/internal/configs" + "github.com/hashicorp/terraform/internal/dag" + "github.com/hashicorp/terraform/internal/lang/langrefs" +) + +// ConcreteActionTriggerNodeFunc is a callback type used to convert an +// abstract action trigger to a concrete one of some type. +type ConcreteActionTriggerNodeFunc func(*nodeAbstractActionTriggerExpand) dag.Vertex + +type nodeAbstractActionTriggerExpand struct { + Addr addrs.ConfigAction + resolvedProvider addrs.AbsProviderConfig + Config *configs.Action + + lifecycleActionTrigger *lifecycleActionTrigger +} + +type lifecycleActionTrigger struct { + resourceAddress addrs.ConfigResource + events []configs.ActionTriggerEvent + actionTriggerBlockIndex int + actionListIndex int + invokingSubject *hcl.Range + actionExpr hcl.Expression + conditionExpr hcl.Expression +} + +func (at *lifecycleActionTrigger) Name() string { + return fmt.Sprintf("%s.lifecycle.action_trigger[%d].actions[%d]", at.resourceAddress.String(), at.actionTriggerBlockIndex, at.actionListIndex) +} + +var ( + _ GraphNodeReferencer = (*nodeAbstractActionTriggerExpand)(nil) +) + +func (n *nodeAbstractActionTriggerExpand) Name() string { + triggeredBy := "triggered by " + if n.lifecycleActionTrigger != nil { + triggeredBy += n.lifecycleActionTrigger.resourceAddress.String() + } else { + triggeredBy += "unknown" + } + + return fmt.Sprintf("%s %s", n.Addr.String(), triggeredBy) +} + +func (n *nodeAbstractActionTriggerExpand) ModulePath() addrs.Module { + return n.Addr.Module +} + +func (n *nodeAbstractActionTriggerExpand) References() []*addrs.Reference { + var refs []*addrs.Reference + refs = append(refs, &addrs.Reference{ + Subject: n.Addr.Action, + }) + + if n.lifecycleActionTrigger != nil { + refs = append(refs, &addrs.Reference{ + Subject: n.lifecycleActionTrigger.resourceAddress.Resource, + }) + + conditionRefs, _ := langrefs.ReferencesInExpr(addrs.ParseRef, n.lifecycleActionTrigger.conditionExpr) + refs = append(refs, conditionRefs...) + } + + return refs +} + +func (n *nodeAbstractActionTriggerExpand) ProvidedBy() (addr addrs.ProviderConfig, exact bool) { + if n.resolvedProvider.Provider.Type != "" { + return n.resolvedProvider, true + } + + // Since we always have a config, we can use it + relAddr := n.Config.ProviderConfigAddr() + return addrs.LocalProviderConfig{ + LocalName: relAddr.LocalName, + Alias: relAddr.Alias, + }, false +} + +func (n *nodeAbstractActionTriggerExpand) Provider() (provider addrs.Provider) { + return n.Config.Provider +} + +func (n *nodeAbstractActionTriggerExpand) SetProvider(config addrs.AbsProviderConfig) { + n.resolvedProvider = config +} diff --git a/internal/terraform/node_action_trigger_plan.go b/internal/terraform/node_action_trigger_plan.go index e9a2b9885e..2f0b804bac 100644 --- a/internal/terraform/node_action_trigger_plan.go +++ b/internal/terraform/node_action_trigger_plan.go @@ -6,36 +6,15 @@ package terraform import ( "fmt" - "github.com/hashicorp/hcl/v2" "github.com/zclconf/go-cty/cty" "github.com/hashicorp/terraform/internal/addrs" - "github.com/hashicorp/terraform/internal/configs" "github.com/hashicorp/terraform/internal/instances" - "github.com/hashicorp/terraform/internal/lang/langrefs" "github.com/hashicorp/terraform/internal/tfdiags" ) type nodeActionTriggerPlanExpand struct { - Addr addrs.ConfigAction - resolvedProvider addrs.AbsProviderConfig - Config *configs.Action - - lifecycleActionTrigger *lifecycleActionTrigger -} - -type lifecycleActionTrigger struct { - resourceAddress addrs.ConfigResource - events []configs.ActionTriggerEvent - actionTriggerBlockIndex int - actionListIndex int - invokingSubject *hcl.Range - actionExpr hcl.Expression - conditionExpr hcl.Expression -} - -func (at *lifecycleActionTrigger) Name() string { - return fmt.Sprintf("%s.lifecycle.action_trigger[%d].actions[%d]", at.resourceAddress.String(), at.actionTriggerBlockIndex, at.actionListIndex) + *nodeAbstractActionTriggerExpand } var ( @@ -44,14 +23,7 @@ var ( ) func (n *nodeActionTriggerPlanExpand) Name() string { - triggeredBy := "triggered by " - if n.lifecycleActionTrigger != nil { - triggeredBy += n.lifecycleActionTrigger.resourceAddress.String() - } else { - triggeredBy += "unknown" - } - - return fmt.Sprintf("%s %s", n.Addr.String(), triggeredBy) + return fmt.Sprintf("%s (plan)", n.nodeAbstractActionTriggerExpand.Name()) } func (n *nodeActionTriggerPlanExpand) DynamicExpand(ctx EvalContext) (*Graph, tfdiags.Diagnostics) { @@ -148,46 +120,3 @@ func (n *nodeActionTriggerPlanExpand) DynamicExpand(ctx EvalContext) (*Graph, tf addRootNodeToGraph(&g) return &g, diags } - -func (n *nodeActionTriggerPlanExpand) ModulePath() addrs.Module { - return n.Addr.Module -} - -func (n *nodeActionTriggerPlanExpand) References() []*addrs.Reference { - var refs []*addrs.Reference - refs = append(refs, &addrs.Reference{ - Subject: n.Addr.Action, - }) - - if n.lifecycleActionTrigger != nil { - refs = append(refs, &addrs.Reference{ - Subject: n.lifecycleActionTrigger.resourceAddress.Resource, - }) - - conditionRefs, _ := langrefs.ReferencesInExpr(addrs.ParseRef, n.lifecycleActionTrigger.conditionExpr) - refs = append(refs, conditionRefs...) - } - - return refs -} - -func (n *nodeActionTriggerPlanExpand) ProvidedBy() (addr addrs.ProviderConfig, exact bool) { - if n.resolvedProvider.Provider.Type != "" { - return n.resolvedProvider, true - } - - // Since we always have a config, we can use it - relAddr := n.Config.ProviderConfigAddr() - return addrs.LocalProviderConfig{ - LocalName: relAddr.LocalName, - Alias: relAddr.Alias, - }, false -} - -func (n *nodeActionTriggerPlanExpand) Provider() (provider addrs.Provider) { - return n.Config.Provider -} - -func (n *nodeActionTriggerPlanExpand) SetProvider(config addrs.AbsProviderConfig) { - n.resolvedProvider = config -} diff --git a/internal/terraform/transform_action_trigger_config.go b/internal/terraform/transform_action_trigger_config.go index c2be5077b7..8e035350a2 100644 --- a/internal/terraform/transform_action_trigger_config.go +++ b/internal/terraform/transform_action_trigger_config.go @@ -18,6 +18,8 @@ type ActionTriggerConfigTransformer struct { Operation walkOperation queryPlanMode bool + + ConcreteActionTriggerNodeFunc ConcreteActionTriggerNodeFunc } func (t *ActionTriggerConfigTransformer) Transform(g *Graph) error { @@ -69,7 +71,7 @@ func (t *ActionTriggerConfigTransformer) transformSingle(g *Graph, config *confi } for _, r := range config.Module.ManagedResources { - priorNodes := []*nodeActionTriggerPlanExpand{} + priorNodes := []dag.Vertex{} for i, at := range r.Managed.ActionTriggers { for j, action := range at.Actions { refs, parseRefDiags := langrefs.ReferencesInExpr(addrs.ParseRef, action.Expr) @@ -105,7 +107,7 @@ func (t *ActionTriggerConfigTransformer) transformSingle(g *Graph, config *confi panic(fmt.Sprintf("Could not find node for %s", resourceAddr)) } - nat := &nodeActionTriggerPlanExpand{ + abstract := &nodeAbstractActionTriggerExpand{ Addr: configAction, Config: actionConfig, lifecycleActionTrigger: &lifecycleActionTrigger{ @@ -119,6 +121,7 @@ func (t *ActionTriggerConfigTransformer) transformSingle(g *Graph, config *confi }, } + nat := t.ConcreteActionTriggerNodeFunc(abstract) g.Add(nat) // We always want to plan after the resource is done planning