Support for deferred action invocations in plan

We encovered that deferred action invocations don't get provider
addresses, which prevents us from loading the schema. That being said, I
think it shouldn't be an issue, but will come back to revisit this as we
build the support end to end.

Add a test for deferred actions support
pull/38243/head^2
Mutahhir Hayat 2 months ago committed by Daniel Schmidt
parent 5b2f19abad
commit ffeff0914d

@ -207,6 +207,32 @@ func FromPlan(ctx context.Context, config *configs.Config, plan *plans.Plan, ref
})
}
// Handle deferred action invocations from the plan
for _, deferredAction := range plan.DeferredActionInvocations {
invocation := deferredAction.ActionInvocationInstanceSrc
if invocation == nil {
continue
}
// For deferred actions, the provider address is typically empty because
// actions are deferred before being fully evaluated. We create the planned
// change without schema since we can't fetch it without a provider address.
plannedActionInvocation := PlannedChangeActionInvocationInstancePlanned{
ActionInvocationAddr: stackaddrs.AbsActionInvocationInstance{
Component: producer.Addr(),
Item: invocation.Addr,
},
Invocation: invocation,
Schema: providers.ActionSchema{}, // Empty schema for deferred actions
ProviderConfigAddr: invocation.ProviderAddr, // Will be empty, that's expected
}
changes = append(changes, &PlannedChangeDeferredActionInvocation{
DeferredReason: deferredAction.DeferredReason,
ActionInvocationPlanned: plannedActionInvocation,
})
}
// We also need to catch any objects that exist in the "prior state"
// but don't have any actions planned, since we still need to capture
// the prior state part in case it was updated by refreshing during

@ -443,6 +443,8 @@ func plannedChangeSortKey(change stackplan.PlannedChange) string {
return "function-results"
case *stackplan.PlannedChangeActionInvocationInstancePlanned:
return change.ActionInvocationAddr.String()
case *stackplan.PlannedChangeDeferredActionInvocation:
return "deferred:" + change.ActionInvocationPlanned.ActionInvocationAddr.String()
default:
// This is only going to happen during tests, so we can panic here.
panic(fmt.Errorf("unrecognized planned change type: %T", change))

@ -6573,15 +6573,33 @@ func TestPlanWithDeferredActionInvocation(t *testing.T) {
return plannedChangeSortKey(gotChanges[i]) < plannedChangeSortKey(gotChanges[j])
})
// Find the deferred action invocation in the changes
// First, let's verify the resource was actually deferred
var foundDeferredResource bool
var foundNormalActionInvocation bool
var foundDeferredAction bool
for _, change := range gotChanges {
if _, ok := change.(*stackplan.PlannedChangeDeferredActionInvocation); ok {
switch c := change.(type) {
case *stackplan.PlannedChangeDeferredResourceInstancePlanned:
foundDeferredResource = true
t.Logf("Found deferred resource: %s", c.ResourceInstancePlanned.ResourceInstanceObjectAddr)
case *stackplan.PlannedChangeActionInvocationInstancePlanned:
foundNormalActionInvocation = true
t.Logf("Found normal action invocation: %s", c.ActionInvocationAddr)
case *stackplan.PlannedChangeDeferredActionInvocation:
foundDeferredAction = true
break
t.Logf("Found deferred action invocation: %s", c.ActionInvocationPlanned.ActionInvocationAddr)
}
}
if !foundDeferredResource {
t.Error("Expected to find a deferred resource, but none was found")
}
if foundNormalActionInvocation {
t.Error("Action invocation should be deferred, not appearing as a normal invocation")
}
if !foundDeferredAction {
t.Error("Expected to find a deferred action invocation in the plan changes, but none was found")
t.Logf("Got %d changes:", len(gotChanges))

@ -18,7 +18,7 @@ variable "defer" {
type = bool
}
# Action that should be invoked when resource is created
# Simple action
action "testing_action" "notify" {
config {
message = "resource created with id ${var.id}"

Loading…
Cancel
Save