Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions internal/terraform/context_plan_actions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3257,6 +3257,35 @@ resource "test_object" "a" {
}
}

func TestContextPlan_validateActionInTriggerExists(t *testing.T) {
// this validation occurs during TransformConfig
module := `
resource "test_object" "a" {
lifecycle {
action_trigger {
events = [after_create]
actions = [action.act_unlinked.hello]
}
}
}
`
m := testModuleInline(t, map[string]string{"main.tf": module})
p := simpleMockProvider()
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
})

_, diags := ctx.Plan(m, nil, DefaultPlanOpts)
if !diags.HasErrors() {
t.Fatal("expected errors, got success!")
}
if diags.Err().Error() != "Configuration for triggered action does not exist: The configuration for the given action action.act_unlinked.hello does not exist. All triggered actions must have an associated configuration." {
t.Fatal("wrong error!")
}
}

func mustActionInstanceAddr(t *testing.T, address string) addrs.AbsActionInstance {
action, diags := addrs.ParseAbsActionInstanceStr(address)
if len(diags) > 0 {
Expand Down
49 changes: 49 additions & 0 deletions internal/terraform/transform_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"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"
"github.com/hashicorp/terraform/internal/tfdiags"
)

Expand Down Expand Up @@ -131,9 +132,14 @@ func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config) er
}
}

// collect all the Action Declarations (configs.Actions) in this module so
// we can validate that actions referenced in a resource's ActionTriggers
// exist in this module.
allConfigActions := make(map[string]*configs.Action)
for _, a := range module.Actions {
if a != nil {
addr := a.Addr().InModule(path)
allConfigActions[addr.String()] = a
log.Printf("[TRACE] ConfigTransformer: Adding action %s", addr)
abstract := &NodeAbstractAction{
Addr: addr,
Expand Down Expand Up @@ -162,6 +168,49 @@ func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config) er
continue
}

// Verify that any actions referenced in the resource's ActionTriggers exist in this module
var diags tfdiags.Diagnostics
if r.Managed != nil && r.Managed.ActionTriggers != nil {
for i, at := range r.Managed.ActionTriggers {
for _, action := range at.Actions {

refs, parseRefDiags := langrefs.ReferencesInExpr(addrs.ParseRef, action.Expr)
if parseRefDiags != nil {
return parseRefDiags.Err()
}

var configAction addrs.ConfigAction

for _, ref := range refs {
switch a := ref.Subject.(type) {
case addrs.Action:
configAction = a.InModule(config.Path)
case addrs.ActionInstance:
configAction = a.Action.InModule(config.Path)
case addrs.CountAttr, addrs.ForEachAttr:
// nothing to do, these will get evaluated later
default:
// This should have been caught during validation
panic(fmt.Sprintf("unexpected action address %T", a))
}
}

_, ok := allConfigActions[configAction.String()]
if !ok {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Configuration for triggered action does not exist",
Detail: fmt.Sprintf("The configuration for the given action %s does not exist. All triggered actions must have an associated configuration.", configAction.String()),
Subject: &r.Managed.ActionTriggers[i].DeclRange,
})
}
}
}
}
if diags.HasErrors() {
return diags.Err()
}

// If any of the import targets can apply to this node's instances,
// filter them down to the applicable addresses.
var imports []*ImportTarget
Expand Down