diff --git a/internal/command/jsonplan/action_invocations.go b/internal/command/jsonplan/action_invocations.go index cf8fb7bbd3..cfd7975949 100644 --- a/internal/command/jsonplan/action_invocations.go +++ b/internal/command/jsonplan/action_invocations.go @@ -6,9 +6,11 @@ package jsonplan import ( "encoding/json" "fmt" + "sort" "github.com/hashicorp/terraform/internal/lang/marks" "github.com/hashicorp/terraform/internal/plans" + "github.com/hashicorp/terraform/internal/providers" "github.com/hashicorp/terraform/internal/terraform" "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" @@ -161,3 +163,54 @@ func MarshalActionInvocation(action *plans.ActionInvocationInstanceSrc, schemas } return ai, nil } + +// DeferredActionInvocation is a description of an action invocation that has been +// deferred for some reason. +type DeferredActionInvocation struct { + // Reason is the reason why this action was deferred. + Reason string `json:"reason"` + + // Change contains any information we have about the deferred change. + ActionInvocation ActionInvocation `json:"action_invocation"` +} + +func MarshalDeferredActionInvocations(dais []*plans.DeferredActionInvocationSrc, schemas *terraform.Schemas) ([]DeferredActionInvocation, error) { + var deferredInvocations []DeferredActionInvocation + + sortedActions := append([]*plans.DeferredActionInvocationSrc{}, dais...) + sort.Slice(sortedActions, func(i, j int) bool { + return sortedActions[i].ActionInvocationInstanceSrc.Less(sortedActions[j].ActionInvocationInstanceSrc) + }) + + for _, daiSrc := range dais { + ai, err := MarshalActionInvocation(daiSrc.ActionInvocationInstanceSrc, schemas) + if err != nil { + return nil, err + } + + dai := DeferredActionInvocation{ + ActionInvocation: ai, + } + switch daiSrc.DeferredReason { + case providers.DeferredReasonInstanceCountUnknown: + dai.Reason = DeferredReasonInstanceCountUnknown + case providers.DeferredReasonResourceConfigUnknown: + dai.Reason = DeferredReasonResourceConfigUnknown + case providers.DeferredReasonProviderConfigUnknown: + dai.Reason = DeferredReasonProviderConfigUnknown + case providers.DeferredReasonAbsentPrereq: + dai.Reason = DeferredReasonAbsentPrereq + case providers.DeferredReasonDeferredPrereq: + dai.Reason = DeferredReasonDeferredPrereq + default: + // If we find a reason we don't know about, we'll just mark it as + // unknown. This is a bit of a safety net to ensure that we don't + // break if new reasons are introduced in future versions of the + // provider protocol. + dai.Reason = DeferredReasonUnknown + } + + deferredInvocations = append(deferredInvocations, dai) + } + return deferredInvocations, nil +} diff --git a/internal/command/jsonplan/plan.go b/internal/command/jsonplan/plan.go index 5256a52515..62f9d8c641 100644 --- a/internal/command/jsonplan/plan.go +++ b/internal/command/jsonplan/plan.go @@ -64,19 +64,20 @@ type plan struct { PlannedValues stateValues `json:"planned_values,omitempty"` // ResourceDrift and ResourceChanges are sorted in a user-friendly order // that is undefined at this time, but consistent. - ResourceDrift []ResourceChange `json:"resource_drift,omitempty"` - ResourceChanges []ResourceChange `json:"resource_changes,omitempty"` - DeferredChanges []DeferredResourceChange `json:"deferred_changes,omitempty"` - OutputChanges map[string]Change `json:"output_changes,omitempty"` - ActionInvocations []ActionInvocation `json:"action_invocations,omitempty"` - PriorState json.RawMessage `json:"prior_state,omitempty"` - Config json.RawMessage `json:"configuration,omitempty"` - RelevantAttributes []ResourceAttr `json:"relevant_attributes,omitempty"` - Checks json.RawMessage `json:"checks,omitempty"` - Timestamp string `json:"timestamp,omitempty"` - Applyable bool `json:"applyable"` - Complete bool `json:"complete"` - Errored bool `json:"errored"` + ResourceDrift []ResourceChange `json:"resource_drift,omitempty"` + ResourceChanges []ResourceChange `json:"resource_changes,omitempty"` + DeferredChanges []DeferredResourceChange `json:"deferred_changes,omitempty"` + DeferredActionInvocations []DeferredActionInvocation `json:"deferred_action_invocations,omitempty"` + OutputChanges map[string]Change `json:"output_changes,omitempty"` + ActionInvocations []ActionInvocation `json:"action_invocations,omitempty"` + PriorState json.RawMessage `json:"prior_state,omitempty"` + Config json.RawMessage `json:"configuration,omitempty"` + RelevantAttributes []ResourceAttr `json:"relevant_attributes,omitempty"` + Checks json.RawMessage `json:"checks,omitempty"` + Timestamp string `json:"timestamp,omitempty"` + Applyable bool `json:"applyable"` + Complete bool `json:"complete"` + Errored bool `json:"errored"` } func newPlan() *plan { @@ -312,6 +313,13 @@ func Marshal( } } + if p.DeferredActionInvocations != nil { + output.DeferredActionInvocations, err = MarshalDeferredActionInvocations(p.DeferredActionInvocations, schemas) + if err != nil { + return nil, fmt.Errorf("error in marshaling deferred action invocations: %s", err) + } + } + // output.OutputChanges if output.OutputChanges, err = MarshalOutputChanges(p.Changes); err != nil { return nil, fmt.Errorf("error in marshaling output changes: %s", err) diff --git a/internal/plans/action_invocation.go b/internal/plans/action_invocation.go index be46a127ec..0546846378 100644 --- a/internal/plans/action_invocation.go +++ b/internal/plans/action_invocation.go @@ -36,6 +36,8 @@ type ActionTrigger interface { String() string Equals(to ActionTrigger) bool + + Less(other ActionTrigger) bool } type LifecycleActionTrigger struct { @@ -70,6 +72,20 @@ func (t LifecycleActionTrigger) Equals(other ActionTrigger) bool { t.ActionsListIndex == o.ActionsListIndex } +func (t LifecycleActionTrigger) Less(other ActionTrigger) bool { + o, ok := other.(LifecycleActionTrigger) + if !ok { + return false // We always want to show non-lifecycle actions first + } + + return t.TriggeringResourceAddr.Less(o.TriggeringResourceAddr) || + (t.TriggeringResourceAddr.Equal(o.TriggeringResourceAddr) && + t.ActionTriggerBlockIndex < o.ActionTriggerBlockIndex) || + (t.TriggeringResourceAddr.Equal(o.TriggeringResourceAddr) && + t.ActionTriggerBlockIndex == o.ActionTriggerBlockIndex && + t.ActionsListIndex < o.ActionsListIndex) +} + var _ ActionTrigger = (*LifecycleActionTrigger)(nil) // Encode produces a variant of the receiver that has its change values diff --git a/internal/plans/changes_src.go b/internal/plans/changes_src.go index 1548619b53..2c7bd1f2b5 100644 --- a/internal/plans/changes_src.go +++ b/internal/plans/changes_src.go @@ -603,6 +603,13 @@ func (acs *ActionInvocationInstanceSrc) DeepCopy() *ActionInvocationInstanceSrc return &ret } +func (acs *ActionInvocationInstanceSrc) Less(other *ActionInvocationInstanceSrc) bool { + if acs.ActionTrigger.Equals(other.ActionTrigger) { + return acs.Addr.Less(other.Addr) + } + return acs.ActionTrigger.Less(other.ActionTrigger) +} + func (needle *ActionInvocationInstanceSrc) FilterLaterActionInvocations(actionInvocations []*ActionInvocationInstanceSrc) []*ActionInvocationInstanceSrc { needleLat := needle.ActionTrigger.(LifecycleActionTrigger) diff --git a/internal/plans/deferring.go b/internal/plans/deferring.go index 826a4ff362..2ead6dee54 100644 --- a/internal/plans/deferring.go +++ b/internal/plans/deferring.go @@ -52,3 +52,47 @@ func (rcs *DeferredResourceInstanceChange) Encode(schema providers.Schema) (*Def ChangeSrc: change, }, nil } + +// DeferredActionInvocation tracks information about an action invocation +// that has been deferred for some reason. +type DeferredActionInvocation struct { + // DeferredReason is the reason why this action invocation was deferred. + DeferredReason providers.DeferredReason + + // ActionInvocationInstance is the instance of the action invocation that was deferred. + ActionInvocationInstance *ActionInvocationInstance +} + +func (dai *DeferredActionInvocation) Encode(schema *providers.ActionSchema) (*DeferredActionInvocationSrc, error) { + src, err := dai.ActionInvocationInstance.Encode(schema) + if err != nil { + return nil, err + } + + return &DeferredActionInvocationSrc{ + DeferredReason: dai.DeferredReason, + ActionInvocationInstanceSrc: src, + }, nil +} + +// DeferredActionInvocationSrc tracks information about an action invocation +// that has been deferred for some reason. +type DeferredActionInvocationSrc struct { + // DeferredReason is the reason why this action invocation was deferred. + DeferredReason providers.DeferredReason + + // ActionInvocationInstanceSrc is the instance of the action invocation that was deferred. + ActionInvocationInstanceSrc *ActionInvocationInstanceSrc +} + +func (dais *DeferredActionInvocationSrc) Decode(schema *providers.ActionSchema) (*DeferredActionInvocation, error) { + instance, err := dais.ActionInvocationInstanceSrc.Decode(schema) + if err != nil { + return nil, err + } + + return &DeferredActionInvocation{ + DeferredReason: dais.DeferredReason, + ActionInvocationInstance: instance, + }, nil +} diff --git a/internal/plans/deferring/deferred.go b/internal/plans/deferring/deferred.go index d6f9e82eb2..02bc0a150c 100644 --- a/internal/plans/deferring/deferred.go +++ b/internal/plans/deferring/deferred.go @@ -80,6 +80,12 @@ type Deferred struct { // all of those options to decide if each instance is relevant. ephemeralResourceInstancesDeferred addrs.Map[addrs.ConfigResource, addrs.Map[addrs.AbsResourceInstance, *plans.DeferredResourceInstanceChange]] + // actionInvocationDeferred tracks the action invocations that have been + // deferred despite their full addresses being known. This can happen + // either because an upstream change was already deferred, or because + // the action invocation is not yet ready to be executed. + actionInvocationDeferred []*plans.DeferredActionInvocation + // partialExpandedResourcesDeferred tracks placeholders that cover an // unbounded set of potential resource instances in situations where we // don't yet even have enough information to predict which instances of @@ -176,6 +182,11 @@ func (d *Deferred) GetDeferredChanges() []*plans.DeferredResourceInstanceChange return changes } +// GetDeferredActionInvocations returns a list of all deferred action invocations. +func (d *Deferred) GetDeferredActionInvocations() []*plans.DeferredActionInvocation { + return d.actionInvocationDeferred +} + // SetExternalDependencyDeferred modifies a freshly-constructed [Deferred] // so that it will consider all resource instances as needing their actions // deferred, even if there's no other reason to do that. @@ -212,6 +223,7 @@ func (d *Deferred) HaveAnyDeferrals() bool { d.resourceInstancesDeferred.Len() != 0 || d.dataSourceInstancesDeferred.Len() != 0 || d.ephemeralResourceInstancesDeferred.Len() != 0 || + len(d.actionInvocationDeferred) != 0 || d.partialExpandedResourcesDeferred.Len() != 0 || d.partialExpandedDataSourcesDeferred.Len() != 0 || d.partialExpandedEphemeralResourceDeferred.Len() != 0 || @@ -626,8 +638,28 @@ func (d *Deferred) ReportModuleExpansionDeferred(addr addrs.PartialExpandedModul d.partialExpandedModulesDeferred.Add(addr) } +func (d *Deferred) ReportActionInvocationDeferred(ai plans.ActionInvocationInstance, reason providers.DeferredReason) { + d.mu.Lock() + defer d.mu.Unlock() + + // Check if the action invocation is already deferred + for _, deferred := range d.actionInvocationDeferred { + if deferred.ActionInvocationInstance.Equals(&ai) { + // This indicates a bug in the caller, since our graph walk should + // ensure that we visit and evaluate each distinct action invocation + // only once. + panic(fmt.Sprintf("duplicate deferral report for action %s invoked by %s", ai.Addr.String(), ai.ActionTrigger.TriggerEvent().String())) + } + } + + d.actionInvocationDeferred = append(d.actionInvocationDeferred, &plans.DeferredActionInvocation{ + ActionInvocationInstance: &ai, + DeferredReason: reason, + }) +} + // UnexpectedProviderDeferralDiagnostic is a diagnostic that indicates that a // provider was deferred although deferrals were not allowed. -func UnexpectedProviderDeferralDiagnostic(addrs addrs.AbsResourceInstance) tfdiags.Diagnostic { +func UnexpectedProviderDeferralDiagnostic(addrs fmt.Stringer) tfdiags.Diagnostic { return tfdiags.Sourceless(tfdiags.Error, "Provider deferred changes when Terraform did not allow deferrals", fmt.Sprintf("The provider signaled a deferred action for %q, but in this context deferrals are disabled. This is a bug in the provider, please file an issue with the provider developers.", addrs.String())) } diff --git a/internal/plans/plan.go b/internal/plans/plan.go index e80dfbbfe4..435e71132e 100644 --- a/internal/plans/plan.go +++ b/internal/plans/plan.go @@ -66,11 +66,12 @@ type Plan struct { VariableMarks map[string][]cty.PathValueMarks ApplyTimeVariables collections.Set[string] - Changes *ChangesSrc - DriftedResources []*ResourceInstanceChangeSrc - DeferredResources []*DeferredResourceInstanceChangeSrc - TargetAddrs []addrs.Targetable - ForceReplaceAddrs []addrs.AbsResourceInstance + Changes *ChangesSrc + DriftedResources []*ResourceInstanceChangeSrc + DeferredResources []*DeferredResourceInstanceChangeSrc + DeferredActionInvocations []*DeferredActionInvocationSrc + TargetAddrs []addrs.Targetable + ForceReplaceAddrs []addrs.AbsResourceInstance Backend Backend StateStore StateStore diff --git a/internal/plans/planfile/tfplan.go b/internal/plans/planfile/tfplan.go index 142de53daa..e3a138ce26 100644 --- a/internal/plans/planfile/tfplan.go +++ b/internal/plans/planfile/tfplan.go @@ -132,6 +132,15 @@ func readTfplan(r io.Reader) (*plans.Plan, error) { plan.DeferredResources = append(plan.DeferredResources, change) } + for _, rawDAI := range rawPlan.DeferredActionInvocations { + change, err := deferredActionInvocationFromTfplan(rawDAI) + if err != nil { + return nil, err + } + + plan.DeferredActionInvocations = append(plan.DeferredActionInvocations, change) + } + for _, rawRA := range rawPlan.RelevantAttributes { ra, err := resourceAttrFromTfplan(rawRA) if err != nil { @@ -541,6 +550,27 @@ func deferredChangeFromTfplan(dc *planproto.DeferredResourceInstanceChange) (*pl }, nil } +func deferredActionInvocationFromTfplan(dai *planproto.DeferredActionInvocation) (*plans.DeferredActionInvocationSrc, error) { + if dai == nil { + return nil, fmt.Errorf("deferred action invocation object is absent") + } + + actionInvocation, err := actionInvocationFromTfplan(dai.ActionInvocation) + if err != nil { + return nil, err + } + + reason, err := DeferredReasonFromProto(dai.Deferred.Reason) + if err != nil { + return nil, err + } + + return &plans.DeferredActionInvocationSrc{ + DeferredReason: reason, + ActionInvocationInstanceSrc: actionInvocation, + }, nil +} + func DeferredReasonFromProto(reason planproto.DeferredReason) (providers.DeferredReason, error) { switch reason { case planproto.DeferredReason_INSTANCE_COUNT_UNKNOWN: @@ -646,6 +676,14 @@ func writeTfplan(plan *plans.Plan, w io.Writer) error { rawPlan.DeferredChanges = append(rawPlan.DeferredChanges, rawDC) } + for _, dai := range plan.DeferredActionInvocations { + rawDAI, err := deferredActionInvocationToTfplan(dai) + if err != nil { + return err + } + rawPlan.DeferredActionInvocations = append(rawPlan.DeferredActionInvocations, rawDAI) + } + for _, ra := range plan.RelevantAttributes { rawRA, err := resourceAttrToTfplan(ra) if err != nil { @@ -1049,6 +1087,25 @@ func deferredChangeToTfplan(dc *plans.DeferredResourceInstanceChangeSrc) (*planp }, nil } +func deferredActionInvocationToTfplan(dai *plans.DeferredActionInvocationSrc) (*planproto.DeferredActionInvocation, error) { + actionInvocation, err := actionInvocationToTfPlan(dai.ActionInvocationInstanceSrc) + if err != nil { + return nil, err + } + + reason, err := DeferredReasonToProto(dai.DeferredReason) + if err != nil { + return nil, err + } + + return &planproto.DeferredActionInvocation{ + Deferred: &planproto.Deferred{ + Reason: reason, + }, + ActionInvocation: actionInvocation, + }, nil +} + func DeferredReasonToProto(reason providers.DeferredReason) (planproto.DeferredReason, error) { switch reason { case providers.DeferredReasonInstanceCountUnknown: diff --git a/internal/plans/planfile/tfplan_test.go b/internal/plans/planfile/tfplan_test.go index 4998bb77fe..4b17b33e43 100644 --- a/internal/plans/planfile/tfplan_test.go +++ b/internal/plans/planfile/tfplan_test.go @@ -420,6 +420,30 @@ func examplePlanForTest(t *testing.T) *plans.Plan { }, }, }, + DeferredActionInvocations: []*plans.DeferredActionInvocationSrc{ + { + DeferredReason: providers.DeferredReasonDeferredPrereq, + ActionInvocationInstanceSrc: &plans.ActionInvocationInstanceSrc{ + Addr: addrs.Action{Type: "test_unlinked", Name: "generic_action"}.Absolute(addrs.RootModuleInstance).Instance(addrs.NoKey), + ActionTrigger: plans.LifecycleActionTrigger{ + TriggeringResourceAddr: addrs.Resource{ + Mode: addrs.ManagedResourceMode, + Type: "test_thing", + Name: "woot", + }.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance), + ActionTriggerBlockIndex: 1, + ActionsListIndex: 2, + ActionTriggerEvent: configs.AfterCreate, + }, + ProviderAddr: provider, + ConfigValue: mustNewDynamicValue(cty.ObjectVal(map[string]cty.Value{ + "attr": cty.StringVal("value"), + }), cty.Object(map[string]cty.Type{ + "attr": cty.String, + })), + }, + }, + }, RelevantAttributes: []globalref.ResourceAttr{ { Resource: addrs.Resource{ diff --git a/internal/plans/planproto/planfile.pb.go b/internal/plans/planproto/planfile.pb.go index 58a7c0b376..2cdbc1f49c 100644 --- a/internal/plans/planproto/planfile.pb.go +++ b/internal/plans/planproto/planfile.pb.go @@ -405,7 +405,7 @@ func (x CheckResults_Status) Number() protoreflect.EnumNumber { // Deprecated: Use CheckResults_Status.Descriptor instead. func (CheckResults_Status) EnumDescriptor() ([]byte, []int) { - return file_planfile_proto_rawDescGZIP(), []int{8, 0} + return file_planfile_proto_rawDescGZIP(), []int{9, 0} } type CheckResults_ObjectKind int32 @@ -460,7 +460,7 @@ func (x CheckResults_ObjectKind) Number() protoreflect.EnumNumber { // Deprecated: Use CheckResults_ObjectKind.Descriptor instead. func (CheckResults_ObjectKind) EnumDescriptor() ([]byte, []int) { - return file_planfile_proto_rawDescGZIP(), []int{8, 1} + return file_planfile_proto_rawDescGZIP(), []int{9, 1} } // Plan is the root message type for the tfplan file @@ -526,6 +526,11 @@ type Plan struct { // reason. Generally, if complete is set to false there should be entries // in this list. DeferredChanges []*DeferredResourceInstanceChange `protobuf:"bytes,27,rep,name=deferred_changes,json=deferredChanges,proto3" json:"deferred_changes,omitempty"` + // An unordered set of deferred action invocations. These are action invocations that will be + // applied in a subsequent plan, but were deferred in this plan for some + // reason. Generally, if complete is set to false there should be entries + // in this list. + DeferredActionInvocations []*DeferredActionInvocation `protobuf:"bytes,31,rep,name=deferred_action_invocations,json=deferredActionInvocations,proto3" json:"deferred_action_invocations,omitempty"` // An unordered set of proposed changes to outputs in the root module // of the configuration. This set also includes "no action" changes for // outputs that are not changing, as context for detecting inconsistencies @@ -667,6 +672,13 @@ func (x *Plan) GetDeferredChanges() []*DeferredResourceInstanceChange { return nil } +func (x *Plan) GetDeferredActionInvocations() []*DeferredActionInvocation { + if x != nil { + return x.DeferredActionInvocations + } + return nil +} + func (x *Plan) GetOutputChanges() []*OutputChange { if x != nil { return x.OutputChanges @@ -1236,6 +1248,64 @@ func (x *DeferredResourceInstanceChange) GetChange() *ResourceInstanceChange { return nil } +// DeferredActionInvocation represents an action invocation that +// was deferred for some reason. +// It contains the original action invocation that was deferred, along with the reason +// why it was deferred. +type DeferredActionInvocation struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The reason why the action invocation was deferred. + Deferred *Deferred `protobuf:"bytes,1,opt,name=deferred,proto3" json:"deferred,omitempty"` + // The original action invocation that was deferred. + ActionInvocation *ActionInvocationInstance `protobuf:"bytes,2,opt,name=action_invocation,json=actionInvocation,proto3" json:"action_invocation,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeferredActionInvocation) Reset() { + *x = DeferredActionInvocation{} + mi := &file_planfile_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeferredActionInvocation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeferredActionInvocation) ProtoMessage() {} + +func (x *DeferredActionInvocation) ProtoReflect() protoreflect.Message { + mi := &file_planfile_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeferredActionInvocation.ProtoReflect.Descriptor instead. +func (*DeferredActionInvocation) Descriptor() ([]byte, []int) { + return file_planfile_proto_rawDescGZIP(), []int{7} +} + +func (x *DeferredActionInvocation) GetDeferred() *Deferred { + if x != nil { + return x.Deferred + } + return nil +} + +func (x *DeferredActionInvocation) GetActionInvocation() *ActionInvocationInstance { + if x != nil { + return x.ActionInvocation + } + return nil +} + type OutputChange struct { state protoimpl.MessageState `protogen:"open.v1"` // Name of the output as defined in the root module. @@ -1253,7 +1323,7 @@ type OutputChange struct { func (x *OutputChange) Reset() { *x = OutputChange{} - mi := &file_planfile_proto_msgTypes[7] + mi := &file_planfile_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1265,7 +1335,7 @@ func (x *OutputChange) String() string { func (*OutputChange) ProtoMessage() {} func (x *OutputChange) ProtoReflect() protoreflect.Message { - mi := &file_planfile_proto_msgTypes[7] + mi := &file_planfile_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1278,7 +1348,7 @@ func (x *OutputChange) ProtoReflect() protoreflect.Message { // Deprecated: Use OutputChange.ProtoReflect.Descriptor instead. func (*OutputChange) Descriptor() ([]byte, []int) { - return file_planfile_proto_rawDescGZIP(), []int{7} + return file_planfile_proto_rawDescGZIP(), []int{8} } func (x *OutputChange) GetName() string { @@ -1319,7 +1389,7 @@ type CheckResults struct { func (x *CheckResults) Reset() { *x = CheckResults{} - mi := &file_planfile_proto_msgTypes[8] + mi := &file_planfile_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1331,7 +1401,7 @@ func (x *CheckResults) String() string { func (*CheckResults) ProtoMessage() {} func (x *CheckResults) ProtoReflect() protoreflect.Message { - mi := &file_planfile_proto_msgTypes[8] + mi := &file_planfile_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1344,7 +1414,7 @@ func (x *CheckResults) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckResults.ProtoReflect.Descriptor instead. func (*CheckResults) Descriptor() ([]byte, []int) { - return file_planfile_proto_rawDescGZIP(), []int{8} + return file_planfile_proto_rawDescGZIP(), []int{9} } func (x *CheckResults) GetKind() CheckResults_ObjectKind { @@ -1388,7 +1458,7 @@ type FunctionCallHash struct { func (x *FunctionCallHash) Reset() { *x = FunctionCallHash{} - mi := &file_planfile_proto_msgTypes[9] + mi := &file_planfile_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1400,7 +1470,7 @@ func (x *FunctionCallHash) String() string { func (*FunctionCallHash) ProtoMessage() {} func (x *FunctionCallHash) ProtoReflect() protoreflect.Message { - mi := &file_planfile_proto_msgTypes[9] + mi := &file_planfile_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1413,7 +1483,7 @@ func (x *FunctionCallHash) ProtoReflect() protoreflect.Message { // Deprecated: Use FunctionCallHash.ProtoReflect.Descriptor instead. func (*FunctionCallHash) Descriptor() ([]byte, []int) { - return file_planfile_proto_rawDescGZIP(), []int{9} + return file_planfile_proto_rawDescGZIP(), []int{10} } func (x *FunctionCallHash) GetKey() []byte { @@ -1451,7 +1521,7 @@ type DynamicValue struct { func (x *DynamicValue) Reset() { *x = DynamicValue{} - mi := &file_planfile_proto_msgTypes[10] + mi := &file_planfile_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1463,7 +1533,7 @@ func (x *DynamicValue) String() string { func (*DynamicValue) ProtoMessage() {} func (x *DynamicValue) ProtoReflect() protoreflect.Message { - mi := &file_planfile_proto_msgTypes[10] + mi := &file_planfile_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1476,7 +1546,7 @@ func (x *DynamicValue) ProtoReflect() protoreflect.Message { // Deprecated: Use DynamicValue.ProtoReflect.Descriptor instead. func (*DynamicValue) Descriptor() ([]byte, []int) { - return file_planfile_proto_rawDescGZIP(), []int{10} + return file_planfile_proto_rawDescGZIP(), []int{11} } func (x *DynamicValue) GetMsgpack() []byte { @@ -1498,7 +1568,7 @@ type Path struct { func (x *Path) Reset() { *x = Path{} - mi := &file_planfile_proto_msgTypes[11] + mi := &file_planfile_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1510,7 +1580,7 @@ func (x *Path) String() string { func (*Path) ProtoMessage() {} func (x *Path) ProtoReflect() protoreflect.Message { - mi := &file_planfile_proto_msgTypes[11] + mi := &file_planfile_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1523,7 +1593,7 @@ func (x *Path) ProtoReflect() protoreflect.Message { // Deprecated: Use Path.ProtoReflect.Descriptor instead. func (*Path) Descriptor() ([]byte, []int) { - return file_planfile_proto_rawDescGZIP(), []int{11} + return file_planfile_proto_rawDescGZIP(), []int{12} } func (x *Path) GetSteps() []*Path_Step { @@ -1549,7 +1619,7 @@ type Importing struct { func (x *Importing) Reset() { *x = Importing{} - mi := &file_planfile_proto_msgTypes[12] + mi := &file_planfile_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1561,7 +1631,7 @@ func (x *Importing) String() string { func (*Importing) ProtoMessage() {} func (x *Importing) ProtoReflect() protoreflect.Message { - mi := &file_planfile_proto_msgTypes[12] + mi := &file_planfile_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1574,7 +1644,7 @@ func (x *Importing) ProtoReflect() protoreflect.Message { // Deprecated: Use Importing.ProtoReflect.Descriptor instead. func (*Importing) Descriptor() ([]byte, []int) { - return file_planfile_proto_rawDescGZIP(), []int{12} + return file_planfile_proto_rawDescGZIP(), []int{13} } func (x *Importing) GetId() string { @@ -1609,7 +1679,7 @@ type Deferred struct { func (x *Deferred) Reset() { *x = Deferred{} - mi := &file_planfile_proto_msgTypes[13] + mi := &file_planfile_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1621,7 +1691,7 @@ func (x *Deferred) String() string { func (*Deferred) ProtoMessage() {} func (x *Deferred) ProtoReflect() protoreflect.Message { - mi := &file_planfile_proto_msgTypes[13] + mi := &file_planfile_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1634,7 +1704,7 @@ func (x *Deferred) ProtoReflect() protoreflect.Message { // Deprecated: Use Deferred.ProtoReflect.Descriptor instead. func (*Deferred) Descriptor() ([]byte, []int) { - return file_planfile_proto_rawDescGZIP(), []int{13} + return file_planfile_proto_rawDescGZIP(), []int{14} } func (x *Deferred) GetReason() DeferredReason { @@ -1665,7 +1735,7 @@ type ActionInvocationInstance struct { func (x *ActionInvocationInstance) Reset() { *x = ActionInvocationInstance{} - mi := &file_planfile_proto_msgTypes[14] + mi := &file_planfile_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1677,7 +1747,7 @@ func (x *ActionInvocationInstance) String() string { func (*ActionInvocationInstance) ProtoMessage() {} func (x *ActionInvocationInstance) ProtoReflect() protoreflect.Message { - mi := &file_planfile_proto_msgTypes[14] + mi := &file_planfile_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1690,7 +1760,7 @@ func (x *ActionInvocationInstance) ProtoReflect() protoreflect.Message { // Deprecated: Use ActionInvocationInstance.ProtoReflect.Descriptor instead. func (*ActionInvocationInstance) Descriptor() ([]byte, []int) { - return file_planfile_proto_rawDescGZIP(), []int{14} + return file_planfile_proto_rawDescGZIP(), []int{15} } func (x *ActionInvocationInstance) GetAddr() string { @@ -1761,7 +1831,7 @@ type LifecycleActionTrigger struct { func (x *LifecycleActionTrigger) Reset() { *x = LifecycleActionTrigger{} - mi := &file_planfile_proto_msgTypes[15] + mi := &file_planfile_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1773,7 +1843,7 @@ func (x *LifecycleActionTrigger) String() string { func (*LifecycleActionTrigger) ProtoMessage() {} func (x *LifecycleActionTrigger) ProtoReflect() protoreflect.Message { - mi := &file_planfile_proto_msgTypes[15] + mi := &file_planfile_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1786,7 +1856,7 @@ func (x *LifecycleActionTrigger) ProtoReflect() protoreflect.Message { // Deprecated: Use LifecycleActionTrigger.ProtoReflect.Descriptor instead. func (*LifecycleActionTrigger) Descriptor() ([]byte, []int) { - return file_planfile_proto_rawDescGZIP(), []int{15} + return file_planfile_proto_rawDescGZIP(), []int{16} } func (x *LifecycleActionTrigger) GetTriggeringResourceAddr() string { @@ -1835,7 +1905,7 @@ type ResourceInstanceActionChange struct { func (x *ResourceInstanceActionChange) Reset() { *x = ResourceInstanceActionChange{} - mi := &file_planfile_proto_msgTypes[16] + mi := &file_planfile_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1847,7 +1917,7 @@ func (x *ResourceInstanceActionChange) String() string { func (*ResourceInstanceActionChange) ProtoMessage() {} func (x *ResourceInstanceActionChange) ProtoReflect() protoreflect.Message { - mi := &file_planfile_proto_msgTypes[16] + mi := &file_planfile_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1860,7 +1930,7 @@ func (x *ResourceInstanceActionChange) ProtoReflect() protoreflect.Message { // Deprecated: Use ResourceInstanceActionChange.ProtoReflect.Descriptor instead. func (*ResourceInstanceActionChange) Descriptor() ([]byte, []int) { - return file_planfile_proto_rawDescGZIP(), []int{16} + return file_planfile_proto_rawDescGZIP(), []int{17} } func (x *ResourceInstanceActionChange) GetAddr() string { @@ -1894,7 +1964,7 @@ type PlanResourceAttr struct { func (x *PlanResourceAttr) Reset() { *x = PlanResourceAttr{} - mi := &file_planfile_proto_msgTypes[18] + mi := &file_planfile_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1906,7 +1976,7 @@ func (x *PlanResourceAttr) String() string { func (*PlanResourceAttr) ProtoMessage() {} func (x *PlanResourceAttr) ProtoReflect() protoreflect.Message { - mi := &file_planfile_proto_msgTypes[18] + mi := &file_planfile_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1947,7 +2017,7 @@ type CheckResults_ObjectResult struct { func (x *CheckResults_ObjectResult) Reset() { *x = CheckResults_ObjectResult{} - mi := &file_planfile_proto_msgTypes[19] + mi := &file_planfile_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1959,7 +2029,7 @@ func (x *CheckResults_ObjectResult) String() string { func (*CheckResults_ObjectResult) ProtoMessage() {} func (x *CheckResults_ObjectResult) ProtoReflect() protoreflect.Message { - mi := &file_planfile_proto_msgTypes[19] + mi := &file_planfile_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1972,7 +2042,7 @@ func (x *CheckResults_ObjectResult) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckResults_ObjectResult.ProtoReflect.Descriptor instead. func (*CheckResults_ObjectResult) Descriptor() ([]byte, []int) { - return file_planfile_proto_rawDescGZIP(), []int{8, 0} + return file_planfile_proto_rawDescGZIP(), []int{9, 0} } func (x *CheckResults_ObjectResult) GetObjectAddr() string { @@ -2009,7 +2079,7 @@ type Path_Step struct { func (x *Path_Step) Reset() { *x = Path_Step{} - mi := &file_planfile_proto_msgTypes[20] + mi := &file_planfile_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2021,7 +2091,7 @@ func (x *Path_Step) String() string { func (*Path_Step) ProtoMessage() {} func (x *Path_Step) ProtoReflect() protoreflect.Message { - mi := &file_planfile_proto_msgTypes[20] + mi := &file_planfile_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2034,7 +2104,7 @@ func (x *Path_Step) ProtoReflect() protoreflect.Message { // Deprecated: Use Path_Step.ProtoReflect.Descriptor instead. func (*Path_Step) Descriptor() ([]byte, []int) { - return file_planfile_proto_rawDescGZIP(), []int{11, 0} + return file_planfile_proto_rawDescGZIP(), []int{12, 0} } func (x *Path_Step) GetSelector() isPath_Step_Selector { @@ -2086,7 +2156,8 @@ var File_planfile_proto protoreflect.FileDescriptor const file_planfile_proto_rawDesc = "" + "\n" + - "\x0eplanfile.proto\x12\x06tfplan\"\xe9\t\n" + + "\x0eplanfile.proto\x12\x06tfplan\"\xcb\n" + + "\n" + "\x04Plan\x12\x18\n" + "\aversion\x18\x01 \x01(\x04R\aversion\x12%\n" + "\aui_mode\x18\x11 \x01(\x0e2\f.tfplan.ModeR\x06uiMode\x12\x1c\n" + @@ -2097,7 +2168,8 @@ const file_planfile_proto_rawDesc = "" + "\x14apply_time_variables\x18\x1c \x03(\tR\x12applyTimeVariables\x12I\n" + "\x10resource_changes\x18\x03 \x03(\v2\x1e.tfplan.ResourceInstanceChangeR\x0fresourceChanges\x12E\n" + "\x0eresource_drift\x18\x12 \x03(\v2\x1e.tfplan.ResourceInstanceChangeR\rresourceDrift\x12Q\n" + - "\x10deferred_changes\x18\x1b \x03(\v2&.tfplan.DeferredResourceInstanceChangeR\x0fdeferredChanges\x12;\n" + + "\x10deferred_changes\x18\x1b \x03(\v2&.tfplan.DeferredResourceInstanceChangeR\x0fdeferredChanges\x12`\n" + + "\x1bdeferred_action_invocations\x18\x1f \x03(\v2 .tfplan.DeferredActionInvocationR\x19deferredActionInvocations\x12;\n" + "\x0eoutput_changes\x18\x04 \x03(\v2\x14.tfplan.OutputChangeR\routputChanges\x129\n" + "\rcheck_results\x18\x13 \x03(\v2\x14.tfplan.CheckResultsR\fcheckResults\x12O\n" + "\x12action_invocations\x18\x1e \x03(\v2 .tfplan.ActionInvocationInstanceR\x11actionInvocations\x12!\n" + @@ -2151,7 +2223,10 @@ const file_planfile_proto_rawDesc = "" + "\raction_reason\x18\f \x01(\x0e2$.tfplan.ResourceInstanceActionReasonR\factionReason\"\x86\x01\n" + "\x1eDeferredResourceInstanceChange\x12,\n" + "\bdeferred\x18\x01 \x01(\v2\x10.tfplan.DeferredR\bdeferred\x126\n" + - "\x06change\x18\x02 \x01(\v2\x1e.tfplan.ResourceInstanceChangeR\x06change\"h\n" + + "\x06change\x18\x02 \x01(\v2\x1e.tfplan.ResourceInstanceChangeR\x06change\"\x97\x01\n" + + "\x18DeferredActionInvocation\x12,\n" + + "\bdeferred\x18\x01 \x01(\v2\x10.tfplan.DeferredR\bdeferred\x12M\n" + + "\x11action_invocation\x18\x02 \x01(\v2 .tfplan.ActionInvocationInstanceR\x10actionInvocation\"h\n" + "\fOutputChange\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12&\n" + "\x06change\x18\x02 \x01(\v2\x0e.tfplan.ChangeR\x06change\x12\x1c\n" + @@ -2280,7 +2355,7 @@ func file_planfile_proto_rawDescGZIP() []byte { } var file_planfile_proto_enumTypes = make([]protoimpl.EnumInfo, 7) -var file_planfile_proto_msgTypes = make([]protoimpl.MessageInfo, 21) +var file_planfile_proto_msgTypes = make([]protoimpl.MessageInfo, 22) var file_planfile_proto_goTypes = []any{ (Mode)(0), // 0: tfplan.Mode (Action)(0), // 1: tfplan.Action @@ -2296,70 +2371,74 @@ var file_planfile_proto_goTypes = []any{ (*Change)(nil), // 11: tfplan.Change (*ResourceInstanceChange)(nil), // 12: tfplan.ResourceInstanceChange (*DeferredResourceInstanceChange)(nil), // 13: tfplan.DeferredResourceInstanceChange - (*OutputChange)(nil), // 14: tfplan.OutputChange - (*CheckResults)(nil), // 15: tfplan.CheckResults - (*FunctionCallHash)(nil), // 16: tfplan.FunctionCallHash - (*DynamicValue)(nil), // 17: tfplan.DynamicValue - (*Path)(nil), // 18: tfplan.Path - (*Importing)(nil), // 19: tfplan.Importing - (*Deferred)(nil), // 20: tfplan.Deferred - (*ActionInvocationInstance)(nil), // 21: tfplan.ActionInvocationInstance - (*LifecycleActionTrigger)(nil), // 22: tfplan.LifecycleActionTrigger - (*ResourceInstanceActionChange)(nil), // 23: tfplan.ResourceInstanceActionChange - nil, // 24: tfplan.Plan.VariablesEntry - (*PlanResourceAttr)(nil), // 25: tfplan.Plan.resource_attr - (*CheckResults_ObjectResult)(nil), // 26: tfplan.CheckResults.ObjectResult - (*Path_Step)(nil), // 27: tfplan.Path.Step + (*DeferredActionInvocation)(nil), // 14: tfplan.DeferredActionInvocation + (*OutputChange)(nil), // 15: tfplan.OutputChange + (*CheckResults)(nil), // 16: tfplan.CheckResults + (*FunctionCallHash)(nil), // 17: tfplan.FunctionCallHash + (*DynamicValue)(nil), // 18: tfplan.DynamicValue + (*Path)(nil), // 19: tfplan.Path + (*Importing)(nil), // 20: tfplan.Importing + (*Deferred)(nil), // 21: tfplan.Deferred + (*ActionInvocationInstance)(nil), // 22: tfplan.ActionInvocationInstance + (*LifecycleActionTrigger)(nil), // 23: tfplan.LifecycleActionTrigger + (*ResourceInstanceActionChange)(nil), // 24: tfplan.ResourceInstanceActionChange + nil, // 25: tfplan.Plan.VariablesEntry + (*PlanResourceAttr)(nil), // 26: tfplan.Plan.resource_attr + (*CheckResults_ObjectResult)(nil), // 27: tfplan.CheckResults.ObjectResult + (*Path_Step)(nil), // 28: tfplan.Path.Step } var file_planfile_proto_depIdxs = []int32{ 0, // 0: tfplan.Plan.ui_mode:type_name -> tfplan.Mode - 24, // 1: tfplan.Plan.variables:type_name -> tfplan.Plan.VariablesEntry + 25, // 1: tfplan.Plan.variables:type_name -> tfplan.Plan.VariablesEntry 12, // 2: tfplan.Plan.resource_changes:type_name -> tfplan.ResourceInstanceChange 12, // 3: tfplan.Plan.resource_drift:type_name -> tfplan.ResourceInstanceChange 13, // 4: tfplan.Plan.deferred_changes:type_name -> tfplan.DeferredResourceInstanceChange - 14, // 5: tfplan.Plan.output_changes:type_name -> tfplan.OutputChange - 15, // 6: tfplan.Plan.check_results:type_name -> tfplan.CheckResults - 21, // 7: tfplan.Plan.action_invocations:type_name -> tfplan.ActionInvocationInstance - 8, // 8: tfplan.Plan.backend:type_name -> tfplan.Backend - 9, // 9: tfplan.Plan.state_store:type_name -> tfplan.StateStore - 25, // 10: tfplan.Plan.relevant_attributes:type_name -> tfplan.Plan.resource_attr - 16, // 11: tfplan.Plan.function_results:type_name -> tfplan.FunctionCallHash - 17, // 12: tfplan.Backend.config:type_name -> tfplan.DynamicValue - 17, // 13: tfplan.StateStore.config:type_name -> tfplan.DynamicValue - 10, // 14: tfplan.StateStore.provider:type_name -> tfplan.Provider - 1, // 15: tfplan.Change.action:type_name -> tfplan.Action - 17, // 16: tfplan.Change.values:type_name -> tfplan.DynamicValue - 18, // 17: tfplan.Change.before_sensitive_paths:type_name -> tfplan.Path - 18, // 18: tfplan.Change.after_sensitive_paths:type_name -> tfplan.Path - 19, // 19: tfplan.Change.importing:type_name -> tfplan.Importing - 17, // 20: tfplan.Change.before_identity:type_name -> tfplan.DynamicValue - 17, // 21: tfplan.Change.after_identity:type_name -> tfplan.DynamicValue - 11, // 22: tfplan.ResourceInstanceChange.change:type_name -> tfplan.Change - 18, // 23: tfplan.ResourceInstanceChange.required_replace:type_name -> tfplan.Path - 2, // 24: tfplan.ResourceInstanceChange.action_reason:type_name -> tfplan.ResourceInstanceActionReason - 20, // 25: tfplan.DeferredResourceInstanceChange.deferred:type_name -> tfplan.Deferred - 12, // 26: tfplan.DeferredResourceInstanceChange.change:type_name -> tfplan.ResourceInstanceChange - 11, // 27: tfplan.OutputChange.change:type_name -> tfplan.Change - 6, // 28: tfplan.CheckResults.kind:type_name -> tfplan.CheckResults.ObjectKind - 5, // 29: tfplan.CheckResults.status:type_name -> tfplan.CheckResults.Status - 26, // 30: tfplan.CheckResults.objects:type_name -> tfplan.CheckResults.ObjectResult - 27, // 31: tfplan.Path.steps:type_name -> tfplan.Path.Step - 17, // 32: tfplan.Importing.identity:type_name -> tfplan.DynamicValue - 3, // 33: tfplan.Deferred.reason:type_name -> tfplan.DeferredReason - 23, // 34: tfplan.ActionInvocationInstance.linked_resources:type_name -> tfplan.ResourceInstanceActionChange - 17, // 35: tfplan.ActionInvocationInstance.config_value:type_name -> tfplan.DynamicValue - 22, // 36: tfplan.ActionInvocationInstance.lifecycle_action_trigger:type_name -> tfplan.LifecycleActionTrigger - 4, // 37: tfplan.LifecycleActionTrigger.trigger_event:type_name -> tfplan.ActionTriggerEvent - 11, // 38: tfplan.ResourceInstanceActionChange.change:type_name -> tfplan.Change - 17, // 39: tfplan.Plan.VariablesEntry.value:type_name -> tfplan.DynamicValue - 18, // 40: tfplan.Plan.resource_attr.attr:type_name -> tfplan.Path - 5, // 41: tfplan.CheckResults.ObjectResult.status:type_name -> tfplan.CheckResults.Status - 17, // 42: tfplan.Path.Step.element_key:type_name -> tfplan.DynamicValue - 43, // [43:43] is the sub-list for method output_type - 43, // [43:43] is the sub-list for method input_type - 43, // [43:43] is the sub-list for extension type_name - 43, // [43:43] is the sub-list for extension extendee - 0, // [0:43] is the sub-list for field type_name + 14, // 5: tfplan.Plan.deferred_action_invocations:type_name -> tfplan.DeferredActionInvocation + 15, // 6: tfplan.Plan.output_changes:type_name -> tfplan.OutputChange + 16, // 7: tfplan.Plan.check_results:type_name -> tfplan.CheckResults + 22, // 8: tfplan.Plan.action_invocations:type_name -> tfplan.ActionInvocationInstance + 8, // 9: tfplan.Plan.backend:type_name -> tfplan.Backend + 9, // 10: tfplan.Plan.state_store:type_name -> tfplan.StateStore + 26, // 11: tfplan.Plan.relevant_attributes:type_name -> tfplan.Plan.resource_attr + 17, // 12: tfplan.Plan.function_results:type_name -> tfplan.FunctionCallHash + 18, // 13: tfplan.Backend.config:type_name -> tfplan.DynamicValue + 18, // 14: tfplan.StateStore.config:type_name -> tfplan.DynamicValue + 10, // 15: tfplan.StateStore.provider:type_name -> tfplan.Provider + 1, // 16: tfplan.Change.action:type_name -> tfplan.Action + 18, // 17: tfplan.Change.values:type_name -> tfplan.DynamicValue + 19, // 18: tfplan.Change.before_sensitive_paths:type_name -> tfplan.Path + 19, // 19: tfplan.Change.after_sensitive_paths:type_name -> tfplan.Path + 20, // 20: tfplan.Change.importing:type_name -> tfplan.Importing + 18, // 21: tfplan.Change.before_identity:type_name -> tfplan.DynamicValue + 18, // 22: tfplan.Change.after_identity:type_name -> tfplan.DynamicValue + 11, // 23: tfplan.ResourceInstanceChange.change:type_name -> tfplan.Change + 19, // 24: tfplan.ResourceInstanceChange.required_replace:type_name -> tfplan.Path + 2, // 25: tfplan.ResourceInstanceChange.action_reason:type_name -> tfplan.ResourceInstanceActionReason + 21, // 26: tfplan.DeferredResourceInstanceChange.deferred:type_name -> tfplan.Deferred + 12, // 27: tfplan.DeferredResourceInstanceChange.change:type_name -> tfplan.ResourceInstanceChange + 21, // 28: tfplan.DeferredActionInvocation.deferred:type_name -> tfplan.Deferred + 22, // 29: tfplan.DeferredActionInvocation.action_invocation:type_name -> tfplan.ActionInvocationInstance + 11, // 30: tfplan.OutputChange.change:type_name -> tfplan.Change + 6, // 31: tfplan.CheckResults.kind:type_name -> tfplan.CheckResults.ObjectKind + 5, // 32: tfplan.CheckResults.status:type_name -> tfplan.CheckResults.Status + 27, // 33: tfplan.CheckResults.objects:type_name -> tfplan.CheckResults.ObjectResult + 28, // 34: tfplan.Path.steps:type_name -> tfplan.Path.Step + 18, // 35: tfplan.Importing.identity:type_name -> tfplan.DynamicValue + 3, // 36: tfplan.Deferred.reason:type_name -> tfplan.DeferredReason + 24, // 37: tfplan.ActionInvocationInstance.linked_resources:type_name -> tfplan.ResourceInstanceActionChange + 18, // 38: tfplan.ActionInvocationInstance.config_value:type_name -> tfplan.DynamicValue + 23, // 39: tfplan.ActionInvocationInstance.lifecycle_action_trigger:type_name -> tfplan.LifecycleActionTrigger + 4, // 40: tfplan.LifecycleActionTrigger.trigger_event:type_name -> tfplan.ActionTriggerEvent + 11, // 41: tfplan.ResourceInstanceActionChange.change:type_name -> tfplan.Change + 18, // 42: tfplan.Plan.VariablesEntry.value:type_name -> tfplan.DynamicValue + 19, // 43: tfplan.Plan.resource_attr.attr:type_name -> tfplan.Path + 5, // 44: tfplan.CheckResults.ObjectResult.status:type_name -> tfplan.CheckResults.Status + 18, // 45: tfplan.Path.Step.element_key:type_name -> tfplan.DynamicValue + 46, // [46:46] is the sub-list for method output_type + 46, // [46:46] is the sub-list for method input_type + 46, // [46:46] is the sub-list for extension type_name + 46, // [46:46] is the sub-list for extension extendee + 0, // [0:46] is the sub-list for field type_name } func init() { file_planfile_proto_init() } @@ -2367,10 +2446,10 @@ func file_planfile_proto_init() { if File_planfile_proto != nil { return } - file_planfile_proto_msgTypes[14].OneofWrappers = []any{ + file_planfile_proto_msgTypes[15].OneofWrappers = []any{ (*ActionInvocationInstance_LifecycleActionTrigger)(nil), } - file_planfile_proto_msgTypes[20].OneofWrappers = []any{ + file_planfile_proto_msgTypes[21].OneofWrappers = []any{ (*Path_Step_AttributeName)(nil), (*Path_Step_ElementKey)(nil), } @@ -2380,7 +2459,7 @@ func file_planfile_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_planfile_proto_rawDesc), len(file_planfile_proto_rawDesc)), NumEnums: 7, - NumMessages: 21, + NumMessages: 22, NumExtensions: 0, NumServices: 0, }, diff --git a/internal/plans/planproto/planfile.proto b/internal/plans/planproto/planfile.proto index c1576b434b..05db4d4bc8 100644 --- a/internal/plans/planproto/planfile.proto +++ b/internal/plans/planproto/planfile.proto @@ -80,6 +80,12 @@ message Plan { // in this list. repeated DeferredResourceInstanceChange deferred_changes = 27; + // An unordered set of deferred action invocations. These are action invocations that will be + // applied in a subsequent plan, but were deferred in this plan for some + // reason. Generally, if complete is set to false there should be entries + // in this list. + repeated DeferredActionInvocation deferred_action_invocations = 31; + // An unordered set of proposed changes to outputs in the root module // of the configuration. This set also includes "no action" changes for // outputs that are not changing, as context for detecting inconsistencies @@ -302,6 +308,18 @@ message DeferredResourceInstanceChange { ResourceInstanceChange change = 2; } +// DeferredActionInvocation represents an action invocation that +// was deferred for some reason. +// It contains the original action invocation that was deferred, along with the reason +// why it was deferred. +message DeferredActionInvocation { + // The reason why the action invocation was deferred. + Deferred deferred = 1; + + // The original action invocation that was deferred. + ActionInvocationInstance action_invocation = 2; +} + message OutputChange { // Name of the output as defined in the root module. string name = 1; diff --git a/internal/terraform/context_plan.go b/internal/terraform/context_plan.go index 94aa7d94eb..155b26f3b7 100644 --- a/internal/terraform/context_plan.go +++ b/internal/terraform/context_plan.go @@ -800,9 +800,6 @@ func (c *Context) planWalk(config *configs.Config, prevRunState *states.State, o driftedResources, driftDiags := c.driftedResources(config, prevRunState, priorState, moveResults) diags = diags.Append(driftDiags) - deferredResources, deferredDiags := c.deferredResources(config, walker.Deferrals.GetDeferredChanges(), priorState) - diags = diags.Append(deferredDiags) - var forgottenResources []string for _, rc := range changes.Resources { if rc.Action == plans.Forget { @@ -832,7 +829,6 @@ func (c *Context) planWalk(config *configs.Config, prevRunState *states.State, o UIMode: opts.Mode, Changes: changesSrc, DriftedResources: driftedResources, - DeferredResources: deferredResources, PrevRunState: prevRunState, PriorState: priorState, ExternalReferences: opts.ExternalReferences, @@ -844,6 +840,16 @@ func (c *Context) planWalk(config *configs.Config, prevRunState *states.State, o // Other fields get populated by Context.Plan after we return } + if !schemaDiags.HasErrors() { + deferredResources, deferredDiags := c.deferredResources(config, walker.Deferrals.GetDeferredChanges(), priorState) + diags = diags.Append(deferredDiags) + plan.DeferredResources = deferredResources + + deferredActionInvocations, deferredActionInvocationsDiags := c.deferredActionInvocations(schemas, walker.Deferrals.GetDeferredActionInvocations()) + diags = diags.Append(deferredActionInvocationsDiags) + plan.DeferredActionInvocations = deferredActionInvocations + } + // Our final rulings on whether the plan is "complete" and "applyable". // See the documentation for these plan fields to learn what exactly they // are intended to mean. @@ -913,6 +919,26 @@ func (c *Context) deferredResources(config *configs.Config, deferrals []*plans.D return deferredResources, diags } +func (c *Context) deferredActionInvocations(schemas *Schemas, deferrals []*plans.DeferredActionInvocation) ([]*plans.DeferredActionInvocationSrc, tfdiags.Diagnostics) { + var deferredActionInvocations []*plans.DeferredActionInvocationSrc + var diags tfdiags.Diagnostics + for _, deferral := range deferrals { + schema := schemas.ActionTypeConfig(deferral.ActionInvocationInstance.ProviderAddr.Provider, deferral.ActionInvocationInstance.Addr.Action.Action.Type) + + deferralSrc, err := deferral.Encode(&schema) + if err != nil { + diags = diags.Append(tfdiags.Sourceless( + tfdiags.Error, + "Failed to prepare deferred action invocation for plan", + fmt.Sprintf("The deferred action invocation %q could not be serialized to store in the plan: %s.", deferral.ActionInvocationInstance.Addr, err))) + continue + } + + deferredActionInvocations = append(deferredActionInvocations, deferralSrc) + } + return deferredActionInvocations, diags +} + func (c *Context) planGraph(config *configs.Config, prevRunState *states.State, opts *PlanOpts) (*Graph, walkOperation, tfdiags.Diagnostics) { var externalProviderConfigs map[addrs.RootProviderConfig]providers.Interface if opts != nil {