Skip to content

Commit 93c5ace

Browse files
authored
Implement GenerateResourceConfig RPC (#350)
* Implement `GenerateResourceConfig` RPC * Add changelog entry * Update terraform-plugin-go dependency to v0.31.0 * Update `go.sum`
1 parent 33c57a0 commit 93c5ace

23 files changed

+592
-6
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
kind: FEATURES
2+
body: 'all: Upgraded protocols and added types to support `GenerateResourceConfig` RPC.'
3+
time: 2026-02-24T16:35:44.444092-05:00
4+
custom:
5+
Issue: "350"

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ go 1.25.0
44

55
require (
66
github.com/google/go-cmp v0.7.0
7-
github.com/hashicorp/terraform-plugin-go v0.30.0
7+
github.com/hashicorp/terraform-plugin-go v0.31.0
88
github.com/hashicorp/terraform-plugin-log v0.10.0
9-
google.golang.org/grpc v1.79.1
9+
google.golang.org/grpc v1.79.2
1010
)
1111

1212
require (

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshf
2525
github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8=
2626
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
2727
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
28-
github.com/hashicorp/terraform-plugin-go v0.30.0 h1:VmEiD0n/ewxbvV5VI/bYwNtlSEAXtHaZlSnyUUuQK6k=
29-
github.com/hashicorp/terraform-plugin-go v0.30.0/go.mod h1:8d523ORAW8OHgA9e8JKg0ezL3XUO84H0A25o4NY/jRo=
28+
github.com/hashicorp/terraform-plugin-go v0.31.0 h1:0Fz2r9DQ+kNNl6bx8HRxFd1TfMKUvnrOtvJPmp3Z0q8=
29+
github.com/hashicorp/terraform-plugin-go v0.31.0/go.mod h1:A88bDhd/cW7FnwqxQRz3slT+QY6yzbHKc6AOTtmdeS8=
3030
github.com/hashicorp/terraform-plugin-log v0.10.0 h1:eu2kW6/QBVdN4P3Ju2WiB2W3ObjkAsyfBsL3Wh1fj3g=
3131
github.com/hashicorp/terraform-plugin-log v0.10.0/go.mod h1:/9RR5Cv2aAbrqcTSdNmY1NRHP4E3ekrXRGjqORpXyB0=
3232
github.com/hashicorp/terraform-registry-address v0.4.0 h1:S1yCGomj30Sao4l5BMPjTGZmCNzuv7/GDTDX99E9gTk=
@@ -90,8 +90,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
9090
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
9191
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
9292
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
93-
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
94-
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
93+
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
94+
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
9595
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
9696
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
9797
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

internal/tf5testserver/tf5testserver.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ type TestServer struct {
7474
PlanActionCalled map[string]bool
7575

7676
InvokeActionCalled map[string]bool
77+
78+
GenerateResourceConfigCalled map[string]bool
7779
}
7880

7981
func (s *TestServer) ProviderServer() tfprotov5.ProviderServer {
@@ -328,3 +330,12 @@ func (s *TestServer) InvokeAction(ctx context.Context, req *tfprotov5.InvokeActi
328330
s.InvokeActionCalled[req.ActionType] = true
329331
return nil, nil
330332
}
333+
334+
func (s *TestServer) GenerateResourceConfig(ctx context.Context, req *tfprotov5.GenerateResourceConfigRequest) (*tfprotov5.GenerateResourceConfigResponse, error) {
335+
if s.GenerateResourceConfigCalled == nil {
336+
s.GenerateResourceConfigCalled = make(map[string]bool)
337+
}
338+
339+
s.GenerateResourceConfigCalled[req.TypeName] = true
340+
return nil, nil
341+
}

internal/tf6testserver/tf6testserver.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ type TestServer struct {
9090
LockStateCalled map[string]bool
9191

9292
UnlockStateCalled map[string]bool
93+
94+
GenerateResourceConfigCalled map[string]bool
9395
}
9496

9597
func (s *TestServer) ProviderServer() tfprotov6.ProviderServer {
@@ -425,3 +427,12 @@ func (s *TestServer) UnlockState(_ context.Context, req *tfprotov6.UnlockStateRe
425427
s.UnlockStateCalled[req.TypeName] = true
426428
return nil, nil
427429
}
430+
431+
func (s *TestServer) GenerateResourceConfig(ctx context.Context, req *tfprotov6.GenerateResourceConfigRequest) (*tfprotov6.GenerateResourceConfigResponse, error) {
432+
if s.GenerateResourceConfigCalled == nil {
433+
s.GenerateResourceConfigCalled = make(map[string]bool)
434+
}
435+
436+
s.GenerateResourceConfigCalled[req.TypeName] = true
437+
return nil, nil
438+
}

internal/tfprotov5tov6/tfprotov5tov6.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,3 +1202,25 @@ func InvokeActionEvent(in tfprotov5.InvokeActionEvent) tfprotov6.InvokeActionEve
12021202
// as a new case above.
12031203
panic(fmt.Sprintf("unimplemented tfprotov5.InvokeActionEventType type: %T", in.Type))
12041204
}
1205+
1206+
func GenerateResourceConfigRequest(in *tfprotov5.GenerateResourceConfigRequest) *tfprotov6.GenerateResourceConfigRequest {
1207+
if in == nil {
1208+
return nil
1209+
}
1210+
1211+
return &tfprotov6.GenerateResourceConfigRequest{
1212+
TypeName: in.TypeName,
1213+
State: DynamicValue(in.State),
1214+
}
1215+
}
1216+
1217+
func GenerateResourceConfigResponse(in *tfprotov5.GenerateResourceConfigResponse) *tfprotov6.GenerateResourceConfigResponse {
1218+
if in == nil {
1219+
return nil
1220+
}
1221+
1222+
return &tfprotov6.GenerateResourceConfigResponse{
1223+
Config: DynamicValue(in.Config),
1224+
Diagnostics: Diagnostics(in.Diagnostics),
1225+
}
1226+
}

internal/tfprotov5tov6/tfprotov5tov6_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3479,6 +3479,80 @@ func TestInvokeActionServerStream(t *testing.T) {
34793479
}
34803480
}
34813481

3482+
func TestGenerateResourceConfigRequest(t *testing.T) {
3483+
t.Parallel()
3484+
3485+
testCases := map[string]struct {
3486+
in *tfprotov5.GenerateResourceConfigRequest
3487+
expected *tfprotov6.GenerateResourceConfigRequest
3488+
}{
3489+
"nil": {
3490+
in: nil,
3491+
expected: nil,
3492+
},
3493+
"all-valid-fields": {
3494+
in: &tfprotov5.GenerateResourceConfigRequest{
3495+
TypeName: "test_resource",
3496+
State: &testTfprotov5DynamicValue,
3497+
},
3498+
expected: &tfprotov6.GenerateResourceConfigRequest{
3499+
TypeName: "test_resource",
3500+
State: &testTfprotov6DynamicValue,
3501+
},
3502+
},
3503+
}
3504+
3505+
for name, testCase := range testCases {
3506+
3507+
t.Run(name, func(t *testing.T) {
3508+
t.Parallel()
3509+
3510+
got := tfprotov5tov6.GenerateResourceConfigRequest(testCase.in)
3511+
3512+
if diff := cmp.Diff(got, testCase.expected); diff != "" {
3513+
t.Errorf("unexpected difference: %s", diff)
3514+
}
3515+
})
3516+
}
3517+
}
3518+
3519+
func TestGenerateResourceConfigResponse(t *testing.T) {
3520+
t.Parallel()
3521+
3522+
testCases := map[string]struct {
3523+
in *tfprotov5.GenerateResourceConfigResponse
3524+
expected *tfprotov6.GenerateResourceConfigResponse
3525+
}{
3526+
"nil": {
3527+
in: nil,
3528+
expected: nil,
3529+
},
3530+
"all-valid-fields": {
3531+
in: &tfprotov5.GenerateResourceConfigResponse{
3532+
Config: &testTfprotov5DynamicValue,
3533+
Diagnostics: testTfprotov5Diagnostics,
3534+
},
3535+
expected: &tfprotov6.GenerateResourceConfigResponse{
3536+
Config: &testTfprotov6DynamicValue,
3537+
Diagnostics: testTfprotov6Diagnostics,
3538+
},
3539+
},
3540+
}
3541+
3542+
for name, testCase := range testCases {
3543+
3544+
t.Run(name, func(t *testing.T) {
3545+
t.Parallel()
3546+
3547+
got := tfprotov5tov6.GenerateResourceConfigResponse(testCase.in)
3548+
3549+
if diff := cmp.Diff(got, testCase.expected); diff != "" {
3550+
t.Errorf("unexpected difference: %s", diff)
3551+
}
3552+
})
3553+
}
3554+
}
3555+
34823556
func pointer[T any](value T) *T {
34833557
return &value
34843558
}

internal/tfprotov6tov5/tfprotov6tov5.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,3 +1279,25 @@ func InvokeActionEvent(in tfprotov6.InvokeActionEvent) tfprotov5.InvokeActionEve
12791279
// as a new case above.
12801280
panic(fmt.Sprintf("unimplemented tfprotov6.InvokeActionEventType type: %T", in.Type))
12811281
}
1282+
1283+
func GenerateResourceConfigRequest(in *tfprotov6.GenerateResourceConfigRequest) *tfprotov5.GenerateResourceConfigRequest {
1284+
if in == nil {
1285+
return nil
1286+
}
1287+
1288+
return &tfprotov5.GenerateResourceConfigRequest{
1289+
TypeName: in.TypeName,
1290+
State: DynamicValue(in.State),
1291+
}
1292+
}
1293+
1294+
func GenerateResourceConfigResponse(in *tfprotov6.GenerateResourceConfigResponse) *tfprotov5.GenerateResourceConfigResponse {
1295+
if in == nil {
1296+
return nil
1297+
}
1298+
1299+
return &tfprotov5.GenerateResourceConfigResponse{
1300+
Config: DynamicValue(in.Config),
1301+
Diagnostics: Diagnostics(in.Diagnostics),
1302+
}
1303+
}

internal/tfprotov6tov5/tfprotov6tov5_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3847,6 +3847,80 @@ func TestInvokeActionServerStream(t *testing.T) {
38473847
}
38483848
}
38493849

3850+
func TestGenerateResourceConfigRequest(t *testing.T) {
3851+
t.Parallel()
3852+
3853+
testCases := map[string]struct {
3854+
in *tfprotov6.GenerateResourceConfigRequest
3855+
expected *tfprotov5.GenerateResourceConfigRequest
3856+
}{
3857+
"nil": {
3858+
in: nil,
3859+
expected: nil,
3860+
},
3861+
"all-valid-fields": {
3862+
in: &tfprotov6.GenerateResourceConfigRequest{
3863+
TypeName: "test_resource",
3864+
State: &testTfprotov6DynamicValue,
3865+
},
3866+
expected: &tfprotov5.GenerateResourceConfigRequest{
3867+
TypeName: "test_resource",
3868+
State: &testTfprotov5DynamicValue,
3869+
},
3870+
},
3871+
}
3872+
3873+
for name, testCase := range testCases {
3874+
3875+
t.Run(name, func(t *testing.T) {
3876+
t.Parallel()
3877+
3878+
got := tfprotov6tov5.GenerateResourceConfigRequest(testCase.in)
3879+
3880+
if diff := cmp.Diff(got, testCase.expected); diff != "" {
3881+
t.Errorf("unexpected difference: %s", diff)
3882+
}
3883+
})
3884+
}
3885+
}
3886+
3887+
func TestGenerateResourceConfigResponse(t *testing.T) {
3888+
t.Parallel()
3889+
3890+
testCases := map[string]struct {
3891+
in *tfprotov6.GenerateResourceConfigResponse
3892+
expected *tfprotov5.GenerateResourceConfigResponse
3893+
}{
3894+
"nil": {
3895+
in: nil,
3896+
expected: nil,
3897+
},
3898+
"all-valid-fields": {
3899+
in: &tfprotov6.GenerateResourceConfigResponse{
3900+
Config: &testTfprotov6DynamicValue,
3901+
Diagnostics: testTfprotov6Diagnostics,
3902+
},
3903+
expected: &tfprotov5.GenerateResourceConfigResponse{
3904+
Config: &testTfprotov5DynamicValue,
3905+
Diagnostics: testTfprotov5Diagnostics,
3906+
},
3907+
},
3908+
}
3909+
3910+
for name, testCase := range testCases {
3911+
3912+
t.Run(name, func(t *testing.T) {
3913+
t.Parallel()
3914+
3915+
got := tfprotov6tov5.GenerateResourceConfigResponse(testCase.in)
3916+
3917+
if diff := cmp.Diff(got, testCase.expected); diff != "" {
3918+
t.Errorf("unexpected difference: %s", diff)
3919+
}
3920+
})
3921+
}
3922+
}
3923+
38503924
func pointer[T any](value T) *T {
38513925
return &value
38523926
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright IBM Corp. 2020, 2026
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package tf5muxserver
5+
6+
import (
7+
"context"
8+
9+
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
10+
11+
"github.com/hashicorp/terraform-plugin-mux/internal/logging"
12+
)
13+
14+
// GenerateResourceConfig calls the GenerateResourceConfig method, passing `req`, on the provider
15+
// that returned the resource specified by req.TypeName in its schema.
16+
func (s *muxServer) GenerateResourceConfig(ctx context.Context, req *tfprotov5.GenerateResourceConfigRequest) (*tfprotov5.GenerateResourceConfigResponse, error) {
17+
rpc := "GenerateResourceConfig"
18+
ctx = logging.InitContext(ctx)
19+
ctx = logging.RpcContext(ctx, rpc)
20+
21+
server, diags, err := s.getResourceServer(ctx, req.TypeName)
22+
23+
if err != nil {
24+
return nil, err
25+
}
26+
27+
if diagnosticsHasError(diags) {
28+
return &tfprotov5.GenerateResourceConfigResponse{
29+
Diagnostics: diags,
30+
}, nil
31+
}
32+
33+
ctx = logging.Tfprotov5ProviderServerContext(ctx, server)
34+
logging.MuxTrace(ctx, "calling downstream server")
35+
36+
return server.GenerateResourceConfig(ctx, req)
37+
}

0 commit comments

Comments
 (0)