Skip to content

Commit 46602a4

Browse files
authored
all: Implement action RPC support in all mux servers (#314)
* update go module + internal 5to6 / 6to5 * tf5muxserver impl actions * fix all list resource references in Go module * tf6muxserver * grammar * 5to6 and 6to5 impl * update to use main
1 parent 9447a02 commit 46602a4

36 files changed

+3162
-51
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ toolchain go1.23.7
66

77
require (
88
github.com/google/go-cmp v0.7.0
9-
github.com/hashicorp/terraform-plugin-go v0.28.1-0.20250616135123-a19df43120ea
9+
github.com/hashicorp/terraform-plugin-go v0.29.0-alpha.1.0.20250709165734-a8477a15f806
1010
github.com/hashicorp/terraform-plugin-log v0.9.0
1111
google.golang.org/grpc v1.73.0
1212
)

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ github.com/hashicorp/go-plugin v1.6.3 h1:xgHB+ZUSYeuJi96WtxEjzi23uh7YQpznjGh0U0U
2121
github.com/hashicorp/go-plugin v1.6.3/go.mod h1:MRobyh+Wc/nYy1V4KAXUiYfzxoYhs7V1mlH1Z7iY2h0=
2222
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
2323
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
24-
github.com/hashicorp/terraform-plugin-go v0.28.1-0.20250616135123-a19df43120ea h1:U9EAAeQtszGlR7mDS7rY77B/a4/XiMDB8HfAtqLAuAQ=
25-
github.com/hashicorp/terraform-plugin-go v0.28.1-0.20250616135123-a19df43120ea/go.mod h1:hL//wLEfYo0YVt0TC/VLzia/ADQQto3HEm4/jX2gkdY=
24+
github.com/hashicorp/terraform-plugin-go v0.29.0-alpha.1.0.20250709165734-a8477a15f806 h1:i3kA1sT/Fk8Ex+VVKdjf9sFOPwS7w3Q73pfbnxKwdjg=
25+
github.com/hashicorp/terraform-plugin-go v0.29.0-alpha.1.0.20250709165734-a8477a15f806/go.mod h1:hL//wLEfYo0YVt0TC/VLzia/ADQQto3HEm4/jX2gkdY=
2626
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
2727
github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
2828
github.com/hashicorp/terraform-registry-address v0.3.0 h1:HMpK3nqaGFPS9VmgRXrJL/dzHNdheGVKk5k7VlFxzCo=

internal/tf5testserver/tf5testserver.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ type TestServer struct {
6868
ValidateListResourceConfigCalled map[string]bool
6969

7070
ListResourceCalled map[string]bool
71+
72+
PlanActionCalled map[string]bool
73+
74+
InvokeActionCalled map[string]bool
7175
}
7276

7377
func (s *TestServer) ProviderServer() tfprotov5.ProviderServer {
@@ -295,3 +299,21 @@ func (s *TestServer) ListResource(_ context.Context, req *tfprotov5.ListResource
295299
s.ListResourceCalled[req.TypeName] = true
296300
return nil, nil
297301
}
302+
303+
func (s *TestServer) PlanAction(ctx context.Context, req *tfprotov5.PlanActionRequest) (*tfprotov5.PlanActionResponse, error) {
304+
if s.PlanActionCalled == nil {
305+
s.PlanActionCalled = make(map[string]bool)
306+
}
307+
308+
s.PlanActionCalled[req.ActionType] = true
309+
return nil, nil
310+
}
311+
312+
func (s *TestServer) InvokeAction(ctx context.Context, req *tfprotov5.InvokeActionRequest) (*tfprotov5.InvokeActionServerStream, error) {
313+
if s.InvokeActionCalled == nil {
314+
s.InvokeActionCalled = make(map[string]bool)
315+
}
316+
317+
s.InvokeActionCalled[req.ActionType] = true
318+
return nil, nil
319+
}

internal/tf6testserver/tf6testserver.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ type TestServer struct {
6868
ValidateListResourceConfigCalled map[string]bool
6969

7070
ListResourceCalled map[string]bool
71+
72+
PlanActionCalled map[string]bool
73+
74+
InvokeActionCalled map[string]bool
7175
}
7276

7377
func (s *TestServer) ProviderServer() tfprotov6.ProviderServer {
@@ -295,3 +299,21 @@ func (s *TestServer) ListResource(_ context.Context, req *tfprotov6.ListResource
295299
s.ListResourceCalled[req.TypeName] = true
296300
return nil, nil
297301
}
302+
303+
func (s *TestServer) PlanAction(ctx context.Context, req *tfprotov6.PlanActionRequest) (*tfprotov6.PlanActionResponse, error) {
304+
if s.PlanActionCalled == nil {
305+
s.PlanActionCalled = make(map[string]bool)
306+
}
307+
308+
s.PlanActionCalled[req.ActionType] = true
309+
return nil, nil
310+
}
311+
312+
func (s *TestServer) InvokeAction(ctx context.Context, req *tfprotov6.InvokeActionRequest) (*tfprotov6.InvokeActionServerStream, error) {
313+
if s.InvokeActionCalled == nil {
314+
s.InvokeActionCalled = make(map[string]bool)
315+
}
316+
317+
s.InvokeActionCalled[req.ActionType] = true
318+
return nil, nil
319+
}

internal/tfprotov5tov6/tfprotov5tov6.go

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
package tfprotov5tov6
55

66
import (
7+
"fmt"
8+
79
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
810
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
911
)
@@ -301,6 +303,7 @@ func GetMetadataResponse(in *tfprotov5.GetMetadataResponse) *tfprotov6.GetMetada
301303
}
302304

303305
resp := &tfprotov6.GetMetadataResponse{
306+
Actions: make([]tfprotov6.ActionMetadata, 0, len(in.Actions)),
304307
DataSources: make([]tfprotov6.DataSourceMetadata, 0, len(in.DataSources)),
305308
Diagnostics: Diagnostics(in.Diagnostics),
306309
EphemeralResources: make([]tfprotov6.EphemeralResourceMetadata, 0, len(in.Resources)),
@@ -330,6 +333,10 @@ func GetMetadataResponse(in *tfprotov5.GetMetadataResponse) *tfprotov6.GetMetada
330333
resp.Resources = append(resp.Resources, ResourceMetadata(resource))
331334
}
332335

336+
for _, action := range in.Actions {
337+
resp.Actions = append(resp.Actions, ActionMetadata(action))
338+
}
339+
333340
return resp
334341
}
335342

@@ -376,7 +383,14 @@ func GetProviderSchemaResponse(in *tfprotov5.GetProviderSchemaResponse) *tfproto
376383
resourceSchemas[k] = Schema(v)
377384
}
378385

386+
actionSchemas := make(map[string]*tfprotov6.ActionSchema, len(in.ActionSchemas))
387+
388+
for k, v := range in.ActionSchemas {
389+
actionSchemas[k] = ActionSchema(v)
390+
}
391+
379392
return &tfprotov6.GetProviderSchemaResponse{
393+
ActionSchemas: actionSchemas,
380394
DataSourceSchemas: dataSourceSchemas,
381395
Diagnostics: Diagnostics(in.Diagnostics),
382396
EphemeralResourceSchemas: ephemeralResourceSchemas,
@@ -1052,3 +1066,244 @@ func ListResourceResult(in tfprotov5.ListResourceResult) tfprotov6.ListResourceR
10521066
Diagnostics: Diagnostics(in.Diagnostics),
10531067
}
10541068
}
1069+
1070+
func ActionMetadata(in tfprotov5.ActionMetadata) tfprotov6.ActionMetadata {
1071+
return tfprotov6.ActionMetadata{
1072+
TypeName: in.TypeName,
1073+
}
1074+
}
1075+
1076+
func ActionSchema(in *tfprotov5.ActionSchema) *tfprotov6.ActionSchema {
1077+
if in == nil {
1078+
return nil
1079+
}
1080+
1081+
actionSchema := &tfprotov6.ActionSchema{
1082+
Schema: Schema(in.Schema),
1083+
}
1084+
1085+
switch actionSchemaType := in.Type.(type) {
1086+
case tfprotov5.UnlinkedActionSchemaType:
1087+
actionSchema.Type = tfprotov6.UnlinkedActionSchemaType{}
1088+
case tfprotov5.LifecycleActionSchemaType:
1089+
actionSchema.Type = tfprotov6.LifecycleActionSchemaType{
1090+
Executes: tfprotov6.LifecycleExecutionOrder(actionSchemaType.Executes),
1091+
LinkedResource: LinkedResourceSchema(actionSchemaType.LinkedResource),
1092+
}
1093+
case tfprotov5.LinkedActionSchemaType:
1094+
actionSchema.Type = tfprotov6.LinkedActionSchemaType{
1095+
LinkedResources: LinkedResourceSchemas(actionSchemaType.LinkedResources),
1096+
}
1097+
default:
1098+
// It is not currently possible to create tfprotov5.ActionSchemaType
1099+
// implementations outside the terraform-plugin-go module. If this panic was reached,
1100+
// it implies that a new event type was introduced and needs to be implemented
1101+
// as a new case above.
1102+
panic(fmt.Sprintf("unimplemented tfprotov5.ActionSchemaType type: %T", in.Type))
1103+
}
1104+
1105+
return actionSchema
1106+
}
1107+
1108+
func LinkedResourceSchemas(in []*tfprotov5.LinkedResourceSchema) []*tfprotov6.LinkedResourceSchema {
1109+
schemas := make([]*tfprotov6.LinkedResourceSchema, 0, len(in))
1110+
1111+
for _, schema := range in {
1112+
schemas = append(schemas, LinkedResourceSchema(schema))
1113+
}
1114+
1115+
return schemas
1116+
}
1117+
1118+
func LinkedResourceSchema(in *tfprotov5.LinkedResourceSchema) *tfprotov6.LinkedResourceSchema {
1119+
if in == nil {
1120+
return nil
1121+
}
1122+
1123+
return &tfprotov6.LinkedResourceSchema{
1124+
TypeName: in.TypeName,
1125+
Description: in.Description,
1126+
}
1127+
}
1128+
1129+
func PlanActionRequest(in *tfprotov5.PlanActionRequest) *tfprotov6.PlanActionRequest {
1130+
if in == nil {
1131+
return nil
1132+
}
1133+
1134+
return &tfprotov6.PlanActionRequest{
1135+
ActionType: in.ActionType,
1136+
LinkedResources: ProposedLinkedResources(in.LinkedResources),
1137+
Config: DynamicValue(in.Config),
1138+
ClientCapabilities: PlanActionClientCapabilities(in.ClientCapabilities),
1139+
}
1140+
}
1141+
1142+
func ProposedLinkedResources(in []*tfprotov5.ProposedLinkedResource) []*tfprotov6.ProposedLinkedResource {
1143+
if in == nil {
1144+
return nil
1145+
}
1146+
1147+
linkedResources := make([]*tfprotov6.ProposedLinkedResource, 0, len(in))
1148+
1149+
for _, inLinkedResource := range in {
1150+
if inLinkedResource == nil {
1151+
linkedResources = append(linkedResources, nil)
1152+
continue
1153+
}
1154+
1155+
linkedResources = append(linkedResources, &tfprotov6.ProposedLinkedResource{
1156+
PriorState: DynamicValue(inLinkedResource.PriorState),
1157+
PlannedState: DynamicValue(inLinkedResource.PlannedState),
1158+
Config: DynamicValue(inLinkedResource.Config),
1159+
PriorIdentity: ResourceIdentityData(inLinkedResource.PriorIdentity),
1160+
})
1161+
}
1162+
1163+
return linkedResources
1164+
}
1165+
1166+
func PlanActionClientCapabilities(in *tfprotov5.PlanActionClientCapabilities) *tfprotov6.PlanActionClientCapabilities {
1167+
if in == nil {
1168+
return nil
1169+
}
1170+
1171+
resp := &tfprotov6.PlanActionClientCapabilities{
1172+
DeferralAllowed: in.DeferralAllowed,
1173+
}
1174+
1175+
return resp
1176+
}
1177+
1178+
func PlanActionResponse(in *tfprotov5.PlanActionResponse) *tfprotov6.PlanActionResponse {
1179+
if in == nil {
1180+
return nil
1181+
}
1182+
1183+
return &tfprotov6.PlanActionResponse{
1184+
LinkedResources: PlannedLinkedResources(in.LinkedResources),
1185+
Diagnostics: Diagnostics(in.Diagnostics),
1186+
Deferred: Deferred(in.Deferred),
1187+
}
1188+
}
1189+
1190+
func PlannedLinkedResources(in []*tfprotov5.PlannedLinkedResource) []*tfprotov6.PlannedLinkedResource {
1191+
if in == nil {
1192+
return nil
1193+
}
1194+
1195+
linkedResources := make([]*tfprotov6.PlannedLinkedResource, 0, len(in))
1196+
1197+
for _, inLinkedResource := range in {
1198+
if inLinkedResource == nil {
1199+
linkedResources = append(linkedResources, nil)
1200+
continue
1201+
}
1202+
1203+
linkedResources = append(linkedResources, &tfprotov6.PlannedLinkedResource{
1204+
PlannedState: DynamicValue(inLinkedResource.PlannedState),
1205+
PlannedIdentity: ResourceIdentityData(inLinkedResource.PlannedIdentity),
1206+
})
1207+
}
1208+
1209+
return linkedResources
1210+
}
1211+
1212+
func InvokeActionRequest(in *tfprotov5.InvokeActionRequest) *tfprotov6.InvokeActionRequest {
1213+
if in == nil {
1214+
return nil
1215+
}
1216+
1217+
return &tfprotov6.InvokeActionRequest{
1218+
ActionType: in.ActionType,
1219+
LinkedResources: InvokeLinkedResources(in.LinkedResources),
1220+
Config: DynamicValue(in.Config),
1221+
}
1222+
}
1223+
1224+
func InvokeLinkedResources(in []*tfprotov5.InvokeLinkedResource) []*tfprotov6.InvokeLinkedResource {
1225+
if in == nil {
1226+
return nil
1227+
}
1228+
1229+
linkedResources := make([]*tfprotov6.InvokeLinkedResource, 0, len(in))
1230+
1231+
for _, inLinkedResource := range in {
1232+
if inLinkedResource == nil {
1233+
linkedResources = append(linkedResources, nil)
1234+
continue
1235+
}
1236+
1237+
linkedResources = append(linkedResources, &tfprotov6.InvokeLinkedResource{
1238+
PriorState: DynamicValue(inLinkedResource.PriorState),
1239+
PlannedState: DynamicValue(inLinkedResource.PlannedState),
1240+
Config: DynamicValue(inLinkedResource.Config),
1241+
PlannedIdentity: ResourceIdentityData(inLinkedResource.PlannedIdentity),
1242+
})
1243+
}
1244+
1245+
return linkedResources
1246+
}
1247+
1248+
func InvokeActionServerStream(in *tfprotov5.InvokeActionServerStream) *tfprotov6.InvokeActionServerStream {
1249+
if in == nil {
1250+
return nil
1251+
}
1252+
1253+
return &tfprotov6.InvokeActionServerStream{
1254+
Events: func(yield func(tfprotov6.InvokeActionEvent) bool) {
1255+
for res := range in.Events {
1256+
if !yield(InvokeActionEvent(res)) {
1257+
break
1258+
}
1259+
}
1260+
},
1261+
}
1262+
}
1263+
1264+
func InvokeActionEvent(in tfprotov5.InvokeActionEvent) tfprotov6.InvokeActionEvent {
1265+
switch event := (in.Type).(type) {
1266+
case tfprotov5.ProgressInvokeActionEventType:
1267+
return tfprotov6.InvokeActionEvent{
1268+
Type: tfprotov6.ProgressInvokeActionEventType{
1269+
Message: event.Message,
1270+
},
1271+
}
1272+
case tfprotov5.CompletedInvokeActionEventType:
1273+
return tfprotov6.InvokeActionEvent{
1274+
Type: tfprotov6.CompletedInvokeActionEventType{
1275+
LinkedResources: NewLinkedResources(event.LinkedResources),
1276+
Diagnostics: Diagnostics(event.Diagnostics),
1277+
},
1278+
}
1279+
}
1280+
1281+
// It is not currently possible to create tfprotov5.InvokeActionEventType
1282+
// implementations outside the terraform-plugin-go module. If this panic was reached,
1283+
// it implies that a new event type was introduced and needs to be implemented
1284+
// as a new case above.
1285+
panic(fmt.Sprintf("unimplemented tfprotov5.InvokeActionEventType type: %T", in.Type))
1286+
}
1287+
1288+
func NewLinkedResources(in []*tfprotov5.NewLinkedResource) []*tfprotov6.NewLinkedResource {
1289+
if in == nil {
1290+
return nil
1291+
}
1292+
1293+
linkedResources := make([]*tfprotov6.NewLinkedResource, 0, len(in))
1294+
1295+
for _, inLinkedResource := range in {
1296+
if inLinkedResource == nil {
1297+
linkedResources = append(linkedResources, nil)
1298+
continue
1299+
}
1300+
1301+
linkedResources = append(linkedResources, &tfprotov6.NewLinkedResource{
1302+
NewState: DynamicValue(inLinkedResource.NewState),
1303+
NewIdentity: ResourceIdentityData(inLinkedResource.NewIdentity),
1304+
RequiresReplace: inLinkedResource.RequiresReplace,
1305+
})
1306+
}
1307+
1308+
return linkedResources
1309+
}

0 commit comments

Comments
 (0)