Skip to content

Commit ad43713

Browse files
track partial expanded action invocations through deferred action invocation
like we do it for resources just simpler because we don't have layered addrs maps
1 parent 68ad276 commit ad43713

File tree

10 files changed

+27
-407
lines changed

10 files changed

+27
-407
lines changed

internal/addrs/partial_expanded.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,16 @@ func (a *AbsAction) UnexpandedAction(action Action) PartialExpandedAction {
924924
}
925925
}
926926

927+
// UnknownActionInstance returns an [AbsActionInstance] that represents the
928+
// same action as the receiver but with all instance keys replaced with a
929+
// wildcard value.
930+
func (per PartialExpandedAction) UnknownActionInstance() AbsActionInstance {
931+
return AbsActionInstance{
932+
Module: per.module.UnknownModuleInstance(),
933+
Action: per.action.Instance(WildcardKey),
934+
}
935+
}
936+
927937
func (pea PartialExpandedAction) String() string {
928938
moduleAddr := pea.module.String()
929939
if len(moduleAddr) != 0 {

internal/command/jsonplan/action_invocations.go

Lines changed: 0 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -234,98 +234,3 @@ func MarshalDeferredActionInvocations(dais []*plans.DeferredActionInvocationSrc,
234234
}
235235
return deferredInvocations, nil
236236
}
237-
238-
func MarshalDeferredPartialActionInvocations(dais []*plans.DeferredPartialExpandedActionInvocationSrc, schemas *terraform.Schemas) ([]DeferredActionInvocation, error) {
239-
var deferredInvocations []DeferredActionInvocation
240-
241-
for _, daiSrc := range dais {
242-
ai, err := MarshalPartialActionInvocation(daiSrc.ActionInvocationInstanceSrc, schemas)
243-
if err != nil {
244-
return nil, err
245-
}
246-
247-
dai := DeferredActionInvocation{
248-
ActionInvocation: ai,
249-
}
250-
switch daiSrc.DeferredReason {
251-
case providers.DeferredReasonInstanceCountUnknown:
252-
dai.Reason = DeferredReasonInstanceCountUnknown
253-
case providers.DeferredReasonResourceConfigUnknown:
254-
dai.Reason = DeferredReasonResourceConfigUnknown
255-
case providers.DeferredReasonProviderConfigUnknown:
256-
dai.Reason = DeferredReasonProviderConfigUnknown
257-
case providers.DeferredReasonAbsentPrereq:
258-
dai.Reason = DeferredReasonAbsentPrereq
259-
case providers.DeferredReasonDeferredPrereq:
260-
dai.Reason = DeferredReasonDeferredPrereq
261-
default:
262-
// If we find a reason we don't know about, we'll just mark it as
263-
// unknown. This is a bit of a safety net to ensure that we don't
264-
// break if new reasons are introduced in future versions of the
265-
// provider protocol.
266-
dai.Reason = DeferredReasonUnknown
267-
}
268-
269-
deferredInvocations = append(deferredInvocations, dai)
270-
}
271-
return deferredInvocations, nil
272-
}
273-
274-
func MarshalPartialActionInvocation(action *plans.PartialExpandedActionInvocationInstanceSrc, schemas *terraform.Schemas) (ActionInvocation, error) {
275-
ai := ActionInvocation{
276-
Address: action.Addr.String(),
277-
Type: action.Addr.ConfigAction().Action.Type,
278-
Name: action.Addr.ConfigAction().Action.Name,
279-
ProviderName: action.ProviderAddr.Provider.String(),
280-
}
281-
schema := schemas.ActionTypeConfig(
282-
action.ProviderAddr.Provider,
283-
action.Addr.ConfigAction().Action.Type,
284-
)
285-
if schema.ConfigSchema == nil {
286-
return ai, fmt.Errorf("no schema found for %s (in provider %s)", action.Addr.ConfigAction().Action.Type, action.ProviderAddr.Provider)
287-
}
288-
289-
actionDec, err := action.Decode(&schema)
290-
if err != nil {
291-
return ai, fmt.Errorf("failed to decode action %s: %w", action.Addr, err)
292-
}
293-
294-
switch at := action.ActionTrigger.(type) {
295-
case plans.PartialLifecycleActionTrigger:
296-
ai.LifecycleActionTrigger = &LifecycleActionTrigger{
297-
TriggeringResourceAddress: at.TriggeringResourceAddr.String(),
298-
ActionTriggerEvent: at.TriggerEvent().String(),
299-
ActionTriggerBlockIndex: at.ActionTriggerBlockIndex,
300-
ActionsListIndex: at.ActionsListIndex,
301-
}
302-
default:
303-
return ai, fmt.Errorf("unsupported action trigger type: %T", at)
304-
}
305-
306-
if actionDec.ConfigValue != cty.NilVal {
307-
_, pvms := actionDec.ConfigValue.UnmarkDeepWithPaths()
308-
sensitivePaths, otherMarks := marks.PathsWithMark(pvms, marks.Sensitive)
309-
ephemeralPaths, otherMarks := marks.PathsWithMark(otherMarks, marks.Ephemeral)
310-
if len(ephemeralPaths) > 0 {
311-
return ai, fmt.Errorf("action %s has ephemeral config values, which are not supported in action invocations", action.Addr)
312-
}
313-
if len(otherMarks) > 0 {
314-
return ai, fmt.Errorf("action %s has config values with unsupported marks: %v", action.Addr, otherMarks)
315-
}
316-
317-
configValue := actionDec.ConfigValue
318-
if !configValue.IsWhollyKnown() {
319-
configValue = omitUnknowns(actionDec.ConfigValue)
320-
}
321-
cs := jsonstate.SensitiveAsBool(marks.MarkPaths(configValue, marks.Sensitive, sensitivePaths))
322-
configSensitive, err := ctyjson.Marshal(cs, cs.Type())
323-
if err != nil {
324-
return ai, err
325-
}
326-
327-
ai.ConfigValues = marshalConfigValues(configValue)
328-
ai.ConfigSensitive = configSensitive
329-
}
330-
return ai, nil
331-
}

internal/command/jsonplan/plan.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -320,14 +320,6 @@ func Marshal(
320320
}
321321
}
322322

323-
if p.DeferredPartialActionInvocations != nil {
324-
deferredPartialActionInvocations, err := MarshalDeferredPartialActionInvocations(p.DeferredPartialActionInvocations, schemas)
325-
if err != nil {
326-
return nil, fmt.Errorf("error in marshaling deferred partial action invocations: %s", err)
327-
}
328-
output.DeferredActionInvocations = append(output.DeferredActionInvocations, deferredPartialActionInvocations...)
329-
}
330-
331323
// output.OutputChanges
332324
if output.OutputChanges, err = MarshalOutputChanges(p.Changes); err != nil {
333325
return nil, fmt.Errorf("error in marshaling output changes: %s", err)

internal/plans/action_invocation.go

Lines changed: 0 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -180,167 +180,3 @@ func (ai *ActionInvocationInstance) DeepCopy() *ActionInvocationInstance {
180180
ret := *ai
181181
return &ret
182182
}
183-
184-
// PartialActionTrigger is the equivalent of ActionTrigger but allows the
185-
// triggering address to be only partially expanded. This is used during earlier
186-
// phases of planning when (for example) count/for_each expansions are not yet
187-
// fully resolved.
188-
type PartialActionTrigger interface {
189-
partialActionTriggerSigil()
190-
191-
TriggerEvent() configs.ActionTriggerEvent
192-
193-
String() string
194-
195-
Equals(other PartialActionTrigger) bool
196-
}
197-
198-
// PartialLifecycleActionTrigger is the partial-expanded form of
199-
// LifecycleActionTrigger. It differs only in that it stores a partial-expanded
200-
// resource instance address for the triggering resource.
201-
type PartialLifecycleActionTrigger struct {
202-
TriggeringResourceAddr addrs.PartialExpandedResource
203-
ActionTriggerEvent configs.ActionTriggerEvent
204-
ActionTriggerBlockIndex int
205-
ActionsListIndex int
206-
}
207-
208-
func (t PartialLifecycleActionTrigger) partialActionTriggerSigil() {}
209-
210-
func (t PartialLifecycleActionTrigger) TriggerEvent() configs.ActionTriggerEvent {
211-
return t.ActionTriggerEvent
212-
}
213-
214-
func (t PartialLifecycleActionTrigger) String() string {
215-
return t.TriggeringResourceAddr.String()
216-
}
217-
218-
func (t PartialLifecycleActionTrigger) Equals(other PartialActionTrigger) bool {
219-
o, ok := other.(*PartialLifecycleActionTrigger)
220-
if !ok {
221-
return false
222-
}
223-
pomt, tIsPartial := t.TriggeringResourceAddr.PartialExpandedModule()
224-
pemo, oIsPartial := o.TriggeringResourceAddr.PartialExpandedModule()
225-
226-
if tIsPartial != oIsPartial {
227-
return false
228-
}
229-
230-
return pomt.MatchesPartial(pemo) && t.TriggeringResourceAddr.Resource().Equal(o.TriggeringResourceAddr.Resource()) &&
231-
t.ActionTriggerEvent == o.ActionTriggerEvent &&
232-
t.ActionTriggerBlockIndex == o.ActionTriggerBlockIndex &&
233-
t.ActionsListIndex == o.ActionsListIndex
234-
}
235-
236-
var _ PartialActionTrigger = (*PartialLifecycleActionTrigger)(nil)
237-
238-
// PartialExpandedActionInvocationInstance mirrors ActionInvocationInstance
239-
// but keeps the action and/or trigger resource addresses in a
240-
// partial-expanded form until all dynamic expansions (count, for_each, etc.)
241-
// are resolved.
242-
type PartialExpandedActionInvocationInstance struct {
243-
Addr addrs.PartialExpandedAction
244-
ActionTrigger PartialActionTrigger
245-
ProviderAddr addrs.AbsProviderConfig
246-
ConfigValue cty.Value
247-
}
248-
249-
// DeepCopy creates a defensive copy of the partial-expanded invocation.
250-
func (pii *PartialExpandedActionInvocationInstance) DeepCopy() *PartialExpandedActionInvocationInstance {
251-
if pii == nil {
252-
return pii
253-
}
254-
ret := *pii
255-
return &ret
256-
}
257-
258-
// Equals compares two partial-expanded invocation instances.
259-
func (pii *PartialExpandedActionInvocationInstance) Equals(other *PartialExpandedActionInvocationInstance) bool {
260-
if pii == nil || other == nil {
261-
return pii == other
262-
}
263-
// We compare the (partial) action address and the trigger (which may also
264-
// embed a partial address).
265-
addrEqual := pii.Addr.Equal(other.Addr)
266-
triggerEqual := false
267-
if pii.ActionTrigger == nil && other.ActionTrigger == nil {
268-
triggerEqual = true
269-
} else if pii.ActionTrigger != nil && other.ActionTrigger != nil {
270-
triggerEqual = pii.ActionTrigger.Equals(other.ActionTrigger)
271-
}
272-
return addrEqual && triggerEqual
273-
}
274-
275-
type PartialExpandedActionInvocationInstanceSrc struct {
276-
Addr addrs.PartialExpandedAction
277-
ActionTrigger PartialActionTrigger
278-
ProviderAddr addrs.AbsProviderConfig
279-
ConfigValue DynamicValue
280-
SensitiveConfigPaths []cty.Path
281-
}
282-
283-
// Encode produces a variant of the receiver that has its config value
284-
// serialized so it can be written to a plan file while action and trigger
285-
// addresses are still in their partial-expanded form. Pass the implied type
286-
// of the corresponding action schema for correct operation.
287-
func (pii *PartialExpandedActionInvocationInstance) Encode(schema *providers.ActionSchema) (*PartialExpandedActionInvocationInstanceSrc, error) {
288-
ret := &PartialExpandedActionInvocationInstanceSrc{
289-
Addr: pii.Addr,
290-
ActionTrigger: pii.ActionTrigger,
291-
ProviderAddr: pii.ProviderAddr,
292-
}
293-
294-
if pii.ConfigValue != cty.NilVal {
295-
ty := cty.DynamicPseudoType
296-
if schema != nil {
297-
ty = schema.ConfigSchema.ImpliedType()
298-
}
299-
300-
unmarkedConfigValue, pvms := pii.ConfigValue.UnmarkDeepWithPaths()
301-
sensitivePaths, otherMarks := marks.PathsWithMark(pvms, marks.Sensitive)
302-
if len(otherMarks) > 0 {
303-
return nil, fmt.Errorf("%s: error serializing partial-expanded action invocation with unexpected marks on config value: %#v. This is a bug in Terraform.", tfdiags.FormatCtyPath(otherMarks[0].Path), otherMarks[0].Marks)
304-
}
305-
306-
var err error
307-
ret.ConfigValue, err = NewDynamicValue(unmarkedConfigValue, ty)
308-
ret.SensitiveConfigPaths = sensitivePaths
309-
if err != nil {
310-
return nil, err
311-
}
312-
}
313-
314-
return ret, nil
315-
}
316-
317-
// Decode produces an in-memory form of the serialized partial-expanded action
318-
// invocation instance using the provided schema to infer the original config
319-
// value type.
320-
func (src *PartialExpandedActionInvocationInstanceSrc) Decode(schema *providers.ActionSchema) (*PartialExpandedActionInvocationInstance, error) {
321-
ret := &PartialExpandedActionInvocationInstance{
322-
Addr: src.Addr,
323-
ActionTrigger: src.ActionTrigger,
324-
ProviderAddr: src.ProviderAddr,
325-
}
326-
327-
if src.ConfigValue != nil {
328-
ty := cty.DynamicPseudoType
329-
if schema != nil {
330-
ty = schema.ConfigSchema.ImpliedType()
331-
}
332-
333-
val, err := src.ConfigValue.Decode(ty)
334-
if err != nil {
335-
return nil, err
336-
}
337-
338-
if len(src.SensitiveConfigPaths) > 0 {
339-
val = marks.MarkPaths(val, marks.Sensitive, src.SensitiveConfigPaths)
340-
}
341-
342-
ret.ConfigValue = val
343-
}
344-
345-
return ret, nil
346-
}

internal/plans/deferring.go

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -96,53 +96,3 @@ func (dais *DeferredActionInvocationSrc) Decode(schema *providers.ActionSchema)
9696
ActionInvocationInstance: instance,
9797
}, nil
9898
}
99-
100-
// DeferredPartialExpandedActionInvocation tracks information about an action
101-
// invocation that has been deferred for some reason, where the underlying
102-
// ActionInvocationInstance contains a partially expanded address (and
103-
// LifecycleActionTrigger).
104-
type DeferredPartialExpandedActionInvocation struct {
105-
// DeferredReason is the reason why this action invocation was deferred.
106-
DeferredReason providers.DeferredReason
107-
108-
// ActionInvocationInstance is the (partially expanded) instance of the action
109-
// invocation that was deferred. Its Addr (and any embedded
110-
// LifecycleActionTrigger addresses) are partial.
111-
ActionInvocationInstance *PartialExpandedActionInvocationInstance
112-
}
113-
114-
func (dai *DeferredPartialExpandedActionInvocation) Encode(schema *providers.ActionSchema) (*DeferredPartialExpandedActionInvocationSrc, error) {
115-
src, err := dai.ActionInvocationInstance.Encode(schema)
116-
if err != nil {
117-
return nil, err
118-
}
119-
120-
return &DeferredPartialExpandedActionInvocationSrc{
121-
DeferredReason: dai.DeferredReason,
122-
ActionInvocationInstanceSrc: src,
123-
}, nil
124-
}
125-
126-
// DeferredPartialExpandedActionInvocationSrc is the serialized form of
127-
// DeferredPartialExpandedActionInvocation.
128-
type DeferredPartialExpandedActionInvocationSrc struct {
129-
// DeferredReason is the reason why this action invocation was deferred.
130-
DeferredReason providers.DeferredReason
131-
132-
// ActionInvocationInstanceSrc is the (partially expanded) instance of the
133-
// action invocation that was deferred. Its Addr (and any embedded
134-
// LifecycleActionTrigger addresses) are partial.
135-
ActionInvocationInstanceSrc *PartialExpandedActionInvocationInstanceSrc
136-
}
137-
138-
func (dais *DeferredPartialExpandedActionInvocationSrc) Decode(schema *providers.ActionSchema) (*DeferredPartialExpandedActionInvocation, error) {
139-
instance, err := dais.ActionInvocationInstanceSrc.Decode(schema)
140-
if err != nil {
141-
return nil, err
142-
}
143-
144-
return &DeferredPartialExpandedActionInvocation{
145-
DeferredReason: dais.DeferredReason,
146-
ActionInvocationInstance: instance,
147-
}, nil
148-
}

0 commit comments

Comments
 (0)