Skip to content

Commit 84dcd0e

Browse files
committed
First pass at including action invocations within stacks proto
1 parent 55615b4 commit 84dcd0e

File tree

9 files changed

+332
-78
lines changed

9 files changed

+332
-78
lines changed

internal/plans/planfile/tfplan.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ import (
2626
"github.com/hashicorp/terraform/version"
2727
)
2828

29-
const tfplanFormatVersion = 3
30-
const tfplanFilename = "tfplan"
29+
const (
30+
tfplanFormatVersion = 3
31+
tfplanFilename = "tfplan"
32+
)
3133

3234
// ---------------------------------------------------------------------------
3335
// This file deals with the internal structure of the "tfplan" sub-file within
@@ -403,7 +405,6 @@ func ActionFromProto(rawAction planproto.Action) (plans.Action, error) {
403405
default:
404406
return plans.NoOp, fmt.Errorf("invalid change action %s", rawAction)
405407
}
406-
407408
}
408409

409410
func changeFromTfplan(rawChange *planproto.Change) (*plans.ChangeSrc, error) {
@@ -1389,6 +1390,10 @@ func actionInvocationFromTfplan(rawAction *planproto.ActionInvocationInstance) (
13891390
return ret, nil
13901391
}
13911392

1393+
func ActionInvocationToProto(action *plans.ActionInvocationInstanceSrc) (*planproto.ActionInvocationInstance, error) {
1394+
return actionInvocationToTfPlan(action)
1395+
}
1396+
13921397
func actionInvocationToTfPlan(action *plans.ActionInvocationInstanceSrc) (*planproto.ActionInvocationInstance, error) {
13931398
if action == nil {
13941399
return nil, nil

internal/rpcapi/terraform1/stacks/conversion.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,10 @@ func NewResourceInstanceObjectInStackAddr(addr stackaddrs.AbsResourceInstanceObj
177177
DeposedKey: addr.Item.DeposedKey.String(),
178178
}
179179
}
180+
181+
func NewActionInvocationInStackAddr(addr stackaddrs.AbsActionInvocationInstance) *ActionInvocationInstanceInStackAddr {
182+
return &ActionInvocationInstanceInStackAddr{
183+
ComponentInstanceAddr: addr.Component.String(),
184+
ActionInvocationInstanceAddr: addr.Item.String(),
185+
}
186+
}

internal/rpcapi/terraform1/stacks/stacks.pb.go

Lines changed: 13 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/rpcapi/terraform1/stacks/stacks.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ message PlannedChange {
539539
bool plan_applyable = 4;
540540
ResourceInstanceDeferred resource_instance_deferred = 5;
541541
InputVariable input_variable_planned = 6;
542-
ActionInvocationInstance action_invocation_instance = 7;
542+
ActionInvocationInstance action_invocation_planned = 7;
543543
}
544544
}
545545

internal/stacks/stackaddrs/in_component.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ type AbsResourceInstance = InAbsComponentInstance[addrs.AbsResourceInstance]
8787
// of a resource from inside a particular component instance.
8888
type AbsResourceInstanceObject = InAbsComponentInstance[addrs.AbsResourceInstanceObject]
8989

90+
// AbsActionInvocationInstance represents an instance of an action from inside a
91+
// particular component instance.
92+
type AbsActionInvocationInstance = InAbsComponentInstance[addrs.AbsActionInstance]
93+
9094
// AbsModuleInstance represents an instance of a module from inside a
9195
// particular component instance.
9296
//

internal/stacks/stackplan/from_plan.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,36 @@ func FromPlan(ctx context.Context, config *configs.Config, plan *plans.Plan, ref
177177
seenObjects.Add(objAddr)
178178
}
179179

180+
// Keep track of Action Invocations
181+
for _, actionChange := range plan.Changes.ActionInvocations {
182+
schema, err := producer.ActionSchema(
183+
ctx,
184+
actionChange.ProviderAddr.Provider,
185+
actionChange.Addr.String(),
186+
)
187+
if err != nil {
188+
diags = diags.Append(tfdiags.Sourceless(
189+
tfdiags.Error,
190+
"Can't fetch provider schema to save plan",
191+
fmt.Sprintf(
192+
"Failed to retrieve the schema for %s from provider %s: %s. This is a bug in Terraform.",
193+
actionChange.Addr, actionChange.ProviderAddr.Provider, err,
194+
),
195+
))
196+
continue
197+
}
198+
199+
changes = append(changes, &PlannedChangeActionInvocationInstancePlanned{
200+
ActionInvocationAddr: stackaddrs.AbsActionInvocationInstance{
201+
Component: producer.Addr(),
202+
Item: actionChange.Addr,
203+
},
204+
Invocation: actionChange,
205+
Schema: schema,
206+
ProviderConfigAddr: actionChange.ProviderAddr,
207+
})
208+
}
209+
180210
// We also need to catch any objects that exist in the "prior state"
181211
// but don't have any actions planned, since we still need to capture
182212
// the prior state part in case it was updated by refreshing during

internal/stacks/stackplan/planned_change.go

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,6 @@ func (pc *PlannedChangeResourceInstancePlanned) ChangeDescription() (*stacks.Pla
493493
},
494494
},
495495
}, nil
496-
497496
}
498497

499498
func DynamicValueToTerraform1(val cty.Value, ty cty.Type) (*stacks.DynamicValue, error) {
@@ -853,3 +852,113 @@ func (pc *PlannedChangeProviderFunctionResults) PlannedChangeProto() (*stacks.Pl
853852
Raw: []*anypb.Any{&raw},
854853
}, nil
855854
}
855+
856+
type PlannedChangeActionInvocationInstancePlanned struct {
857+
ActionInvocationAddr stackaddrs.AbsActionInvocationInstance
858+
859+
// Invocation describes the planned invocation.
860+
Invocation *plans.ActionInvocationInstanceSrc
861+
862+
// ProviderConfigAddr is the address of the provider configuration
863+
// that planned this change, resolved in terms of the configuration for
864+
// the component this resource instance object belongs to.
865+
ProviderConfigAddr addrs.AbsProviderConfig
866+
867+
// Schema MUST be the same schema that was used to encode the dynamic
868+
// values inside ChangeSrc
869+
//
870+
// Can be empty if and only if ChangeSrc is nil.
871+
Schema providers.ActionSchema
872+
}
873+
874+
var _ PlannedChange = (*PlannedChangeActionInvocationInstancePlanned)(nil)
875+
876+
func (pc *PlannedChangeActionInvocationInstancePlanned) PlanActionInvocationProto() (*tfstackdata1.PlanActionInvocationPlanned, error) {
877+
addr := pc.ActionInvocationAddr
878+
879+
if pc.Invocation == nil {
880+
// This is just a stubby placeholder to remind us to drop the
881+
// apparently-deleted-outside-of-Terraform object from the state
882+
// if this plan later gets applied.
883+
884+
return &tfstackdata1.PlanActionInvocationPlanned{
885+
ComponentInstanceAddr: addr.Component.String(),
886+
ActionInvocationAddr: addr.Item.String(),
887+
ProviderConfigAddr: pc.ProviderConfigAddr.String(),
888+
}, nil
889+
}
890+
891+
invocationProto, err := planfile.ActionInvocationToProto(pc.Invocation)
892+
if err != nil {
893+
return nil, fmt.Errorf("converting action invocation to proto: %w", err)
894+
}
895+
896+
return &tfstackdata1.PlanActionInvocationPlanned{
897+
ComponentInstanceAddr: addr.Component.String(),
898+
ActionInvocationAddr: addr.Item.String(),
899+
ProviderConfigAddr: pc.ProviderConfigAddr.String(),
900+
Invocation: invocationProto,
901+
}, nil
902+
}
903+
904+
func (pc *PlannedChangeActionInvocationInstancePlanned) ChangeDescription() (*stacks.PlannedChange_ChangeDescription, error) {
905+
addr := pc.ActionInvocationAddr
906+
907+
// We only emit an external description if there's an invocation to describe.
908+
if pc.Invocation == nil {
909+
return nil, nil
910+
}
911+
912+
return &stacks.PlannedChange_ChangeDescription{
913+
Description: &stacks.PlannedChange_ChangeDescription_ActionInvocationPlanned{
914+
ActionInvocationPlanned: &stacks.PlannedChange_ActionInvocationInstance{
915+
Addr: stacks.NewActionInvocationInStackAddr(addr),
916+
ProviderAddr: pc.Invocation.ProviderAddr.Provider.String(),
917+
918+
ConfigValue: stacks.NewDynamicValue(
919+
pc.Invocation.ConfigValue,
920+
pc.Invocation.SensitiveConfigPaths,
921+
),
922+
923+
ActionTrigger: nil,
924+
},
925+
},
926+
}, nil
927+
}
928+
929+
// PlannedChangeProto implements PlannedChange.
930+
func (pc *PlannedChangeActionInvocationInstancePlanned) PlannedChangeProto() (*stacks.PlannedChange, error) {
931+
paip, err := pc.PlanActionInvocationProto()
932+
if err != nil {
933+
return nil, err
934+
}
935+
var raw anypb.Any
936+
err = anypb.MarshalFrom(&raw, paip, proto.MarshalOptions{})
937+
if err != nil {
938+
return nil, err
939+
}
940+
941+
if pc.Invocation == nil {
942+
// We only emit a "raw" in this case, because this is a relatively
943+
// uninteresting edge-case. The PlanActionInvocationProto
944+
// function should have returned a placeholder value for this use case.
945+
946+
return &stacks.PlannedChange{
947+
Raw: []*anypb.Any{&raw},
948+
}, nil
949+
}
950+
951+
var descs []*stacks.PlannedChange_ChangeDescription
952+
desc, err := pc.ChangeDescription()
953+
if err != nil {
954+
return nil, err
955+
}
956+
if desc != nil {
957+
descs = append(descs, desc)
958+
}
959+
960+
return &stacks.PlannedChange{
961+
Raw: []*anypb.Any{&raw},
962+
Descriptions: descs,
963+
}, nil
964+
}

0 commit comments

Comments
 (0)