Skip to content

Commit fb3849a

Browse files
authored
all: Initial MoveResourceState implementations (#220)
Reference: hashicorp/terraform-plugin-go#364 The next versions of the plugin protocol (5.5/6.5) include support for the MoveResourceState RPC and server capability. This change includes initial implementation of the new RPC in all server implementations.
1 parent 4e0b2f9 commit fb3849a

23 files changed

+819
-0
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: Upgrade protocol versions to support the `MoveResourceState` RPC'
3+
time: 2024-01-26T14:38:40.092759-05:00
4+
custom:
5+
Issue: "220"

internal/tf5testserver/tf5testserver.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ type TestServer struct {
3232

3333
ImportResourceStateCalled map[string]bool
3434

35+
MoveResourceStateCalled map[string]bool
36+
3537
PlanResourceChangeCalled map[string]bool
3638

3739
PrepareProviderConfigCalled bool
@@ -126,6 +128,15 @@ func (s *TestServer) ImportResourceState(_ context.Context, req *tfprotov5.Impor
126128
return nil, nil
127129
}
128130

131+
func (s *TestServer) MoveResourceState(_ context.Context, req *tfprotov5.MoveResourceStateRequest) (*tfprotov5.MoveResourceStateResponse, error) {
132+
if s.MoveResourceStateCalled == nil {
133+
s.MoveResourceStateCalled = make(map[string]bool)
134+
}
135+
136+
s.MoveResourceStateCalled[req.TargetTypeName] = true
137+
return nil, nil
138+
}
139+
129140
func (s *TestServer) PlanResourceChange(_ context.Context, req *tfprotov5.PlanResourceChangeRequest) (*tfprotov5.PlanResourceChangeResponse, error) {
130141
if s.PlanResourceChangeCalled == nil {
131142
s.PlanResourceChangeCalled = make(map[string]bool)

internal/tf6testserver/tf6testserver.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ type TestServer struct {
3232

3333
ImportResourceStateCalled map[string]bool
3434

35+
MoveResourceStateCalled map[string]bool
36+
3537
PlanResourceChangeCalled map[string]bool
3638

3739
ReadDataSourceCalled map[string]bool
@@ -126,6 +128,15 @@ func (s *TestServer) ImportResourceState(_ context.Context, req *tfprotov6.Impor
126128
return nil, nil
127129
}
128130

131+
func (s *TestServer) MoveResourceState(_ context.Context, req *tfprotov6.MoveResourceStateRequest) (*tfprotov6.MoveResourceStateResponse, error) {
132+
if s.MoveResourceStateCalled == nil {
133+
s.MoveResourceStateCalled = make(map[string]bool)
134+
}
135+
136+
s.MoveResourceStateCalled[req.TargetTypeName] = true
137+
return nil, nil
138+
}
139+
129140
func (s *TestServer) PlanResourceChange(_ context.Context, req *tfprotov6.PlanResourceChangeRequest) (*tfprotov6.PlanResourceChangeResponse, error) {
130141
if s.PlanResourceChangeCalled == nil {
131142
s.PlanResourceChangeCalled = make(map[string]bool)

internal/tfprotov5tov6/tfprotov5tov6.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,33 @@ func ImportedResources(in []*tfprotov5.ImportedResource) []*tfprotov6.ImportedRe
327327
return res
328328
}
329329

330+
func MoveResourceStateRequest(in *tfprotov5.MoveResourceStateRequest) *tfprotov6.MoveResourceStateRequest {
331+
if in == nil {
332+
return nil
333+
}
334+
335+
return &tfprotov6.MoveResourceStateRequest{
336+
SourcePrivate: in.SourcePrivate,
337+
SourceProviderAddress: in.SourceProviderAddress,
338+
SourceSchemaVersion: in.SourceSchemaVersion,
339+
SourceState: RawState(in.SourceState),
340+
SourceTypeName: in.SourceTypeName,
341+
TargetTypeName: in.TargetTypeName,
342+
}
343+
}
344+
345+
func MoveResourceStateResponse(in *tfprotov5.MoveResourceStateResponse) *tfprotov6.MoveResourceStateResponse {
346+
if in == nil {
347+
return nil
348+
}
349+
350+
return &tfprotov6.MoveResourceStateResponse{
351+
Diagnostics: Diagnostics(in.Diagnostics),
352+
TargetPrivate: in.TargetPrivate,
353+
TargetState: DynamicValue(in.TargetState),
354+
}
355+
}
356+
330357
func PlanResourceChangeRequest(in *tfprotov5.PlanResourceChangeRequest) *tfprotov6.PlanResourceChangeRequest {
331358
if in == nil {
332359
return nil

internal/tfprotov5tov6/tfprotov5tov6_test.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,96 @@ func TestImportedResources(t *testing.T) {
10301030
}
10311031
}
10321032

1033+
func TestMoveResourceStateRequest(t *testing.T) {
1034+
t.Parallel()
1035+
1036+
testCases := map[string]struct {
1037+
in *tfprotov5.MoveResourceStateRequest
1038+
expected *tfprotov6.MoveResourceStateRequest
1039+
}{
1040+
"nil": {
1041+
in: nil,
1042+
expected: nil,
1043+
},
1044+
"all-valid-fields": {
1045+
in: &tfprotov5.MoveResourceStateRequest{
1046+
SourcePrivate: testBytes,
1047+
SourceProviderAddress: "example.com/namespace/test",
1048+
SourceSchemaVersion: 1,
1049+
SourceState: &tfprotov5.RawState{
1050+
JSON: testBytes,
1051+
},
1052+
SourceTypeName: "test_source",
1053+
TargetTypeName: "test_target",
1054+
},
1055+
expected: &tfprotov6.MoveResourceStateRequest{
1056+
SourcePrivate: testBytes,
1057+
SourceProviderAddress: "example.com/namespace/test",
1058+
SourceSchemaVersion: 1,
1059+
SourceState: &tfprotov6.RawState{
1060+
JSON: testBytes,
1061+
},
1062+
SourceTypeName: "test_source",
1063+
TargetTypeName: "test_target",
1064+
},
1065+
},
1066+
}
1067+
1068+
for name, testCase := range testCases {
1069+
name, testCase := name, testCase
1070+
1071+
t.Run(name, func(t *testing.T) {
1072+
t.Parallel()
1073+
1074+
got := tfprotov5tov6.MoveResourceStateRequest(testCase.in)
1075+
1076+
if diff := cmp.Diff(got, testCase.expected); diff != "" {
1077+
t.Errorf("unexpected difference: %s", diff)
1078+
}
1079+
})
1080+
}
1081+
}
1082+
1083+
func TestMoveResourceStateResponse(t *testing.T) {
1084+
t.Parallel()
1085+
1086+
testCases := map[string]struct {
1087+
in *tfprotov5.MoveResourceStateResponse
1088+
expected *tfprotov6.MoveResourceStateResponse
1089+
}{
1090+
"nil": {
1091+
in: nil,
1092+
expected: nil,
1093+
},
1094+
"all-valid-fields": {
1095+
in: &tfprotov5.MoveResourceStateResponse{
1096+
Diagnostics: testTfprotov5Diagnostics,
1097+
TargetPrivate: testBytes,
1098+
TargetState: &testTfprotov5DynamicValue,
1099+
},
1100+
expected: &tfprotov6.MoveResourceStateResponse{
1101+
Diagnostics: testTfprotov6Diagnostics,
1102+
TargetState: &testTfprotov6DynamicValue,
1103+
TargetPrivate: testBytes,
1104+
},
1105+
},
1106+
}
1107+
1108+
for name, testCase := range testCases {
1109+
name, testCase := name, testCase
1110+
1111+
t.Run(name, func(t *testing.T) {
1112+
t.Parallel()
1113+
1114+
got := tfprotov5tov6.MoveResourceStateResponse(testCase.in)
1115+
1116+
if diff := cmp.Diff(got, testCase.expected); diff != "" {
1117+
t.Errorf("unexpected difference: %s", diff)
1118+
}
1119+
})
1120+
}
1121+
}
1122+
10331123
func TestPlanResourceChangeRequest(t *testing.T) {
10341124
t.Parallel()
10351125

internal/tfprotov6tov5/tfprotov6tov5.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,33 @@ func ImportedResources(in []*tfprotov6.ImportedResource) []*tfprotov5.ImportedRe
355355
return res
356356
}
357357

358+
func MoveResourceStateRequest(in *tfprotov6.MoveResourceStateRequest) *tfprotov5.MoveResourceStateRequest {
359+
if in == nil {
360+
return nil
361+
}
362+
363+
return &tfprotov5.MoveResourceStateRequest{
364+
SourcePrivate: in.SourcePrivate,
365+
SourceProviderAddress: in.SourceProviderAddress,
366+
SourceSchemaVersion: in.SourceSchemaVersion,
367+
SourceState: RawState(in.SourceState),
368+
SourceTypeName: in.SourceTypeName,
369+
TargetTypeName: in.TargetTypeName,
370+
}
371+
}
372+
373+
func MoveResourceStateResponse(in *tfprotov6.MoveResourceStateResponse) *tfprotov5.MoveResourceStateResponse {
374+
if in == nil {
375+
return nil
376+
}
377+
378+
return &tfprotov5.MoveResourceStateResponse{
379+
Diagnostics: Diagnostics(in.Diagnostics),
380+
TargetPrivate: in.TargetPrivate,
381+
TargetState: DynamicValue(in.TargetState),
382+
}
383+
}
384+
358385
func PlanResourceChangeRequest(in *tfprotov6.PlanResourceChangeRequest) *tfprotov5.PlanResourceChangeRequest {
359386
if in == nil {
360387
return nil

internal/tfprotov6tov5/tfprotov6tov5_test.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,6 +1145,96 @@ func TestImportedResources(t *testing.T) {
11451145
}
11461146
}
11471147

1148+
func TestMoveResourceStateRequest(t *testing.T) {
1149+
t.Parallel()
1150+
1151+
testCases := map[string]struct {
1152+
in *tfprotov6.MoveResourceStateRequest
1153+
expected *tfprotov5.MoveResourceStateRequest
1154+
}{
1155+
"nil": {
1156+
in: nil,
1157+
expected: nil,
1158+
},
1159+
"all-valid-fields": {
1160+
in: &tfprotov6.MoveResourceStateRequest{
1161+
SourcePrivate: testBytes,
1162+
SourceProviderAddress: "example.com/namespace/test",
1163+
SourceSchemaVersion: 1,
1164+
SourceState: &tfprotov6.RawState{
1165+
JSON: testBytes,
1166+
},
1167+
SourceTypeName: "test_source",
1168+
TargetTypeName: "test_target",
1169+
},
1170+
expected: &tfprotov5.MoveResourceStateRequest{
1171+
SourcePrivate: testBytes,
1172+
SourceProviderAddress: "example.com/namespace/test",
1173+
SourceSchemaVersion: 1,
1174+
SourceState: &tfprotov5.RawState{
1175+
JSON: testBytes,
1176+
},
1177+
SourceTypeName: "test_source",
1178+
TargetTypeName: "test_target",
1179+
},
1180+
},
1181+
}
1182+
1183+
for name, testCase := range testCases {
1184+
name, testCase := name, testCase
1185+
1186+
t.Run(name, func(t *testing.T) {
1187+
t.Parallel()
1188+
1189+
got := tfprotov6tov5.MoveResourceStateRequest(testCase.in)
1190+
1191+
if diff := cmp.Diff(got, testCase.expected); diff != "" {
1192+
t.Errorf("unexpected difference: %s", diff)
1193+
}
1194+
})
1195+
}
1196+
}
1197+
1198+
func TestMoveResourceStateResponse(t *testing.T) {
1199+
t.Parallel()
1200+
1201+
testCases := map[string]struct {
1202+
in *tfprotov6.MoveResourceStateResponse
1203+
expected *tfprotov5.MoveResourceStateResponse
1204+
}{
1205+
"nil": {
1206+
in: nil,
1207+
expected: nil,
1208+
},
1209+
"all-valid-fields": {
1210+
in: &tfprotov6.MoveResourceStateResponse{
1211+
Diagnostics: testTfprotov6Diagnostics,
1212+
TargetPrivate: testBytes,
1213+
TargetState: &testTfprotov6DynamicValue,
1214+
},
1215+
expected: &tfprotov5.MoveResourceStateResponse{
1216+
Diagnostics: testTfprotov5Diagnostics,
1217+
TargetState: &testTfprotov5DynamicValue,
1218+
TargetPrivate: testBytes,
1219+
},
1220+
},
1221+
}
1222+
1223+
for name, testCase := range testCases {
1224+
name, testCase := name, testCase
1225+
1226+
t.Run(name, func(t *testing.T) {
1227+
t.Parallel()
1228+
1229+
got := tfprotov6tov5.MoveResourceStateResponse(testCase.in)
1230+
1231+
if diff := cmp.Diff(got, testCase.expected); diff != "" {
1232+
t.Errorf("unexpected difference: %s", diff)
1233+
}
1234+
})
1235+
}
1236+
}
1237+
11481238
func TestPlanResourceChangeRequest(t *testing.T) {
11491239
t.Parallel()
11501240

tf5muxserver/mux_server.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ import (
1515

1616
var _ tfprotov5.ProviderServer = &muxServer{}
1717

18+
// Temporarily verify that v5tov6Server implements new RPCs correctly.
19+
// Reference: https://github.com/hashicorp/terraform-plugin-mux/issues/210
20+
// Reference: https://github.com/hashicorp/terraform-plugin-mux/issues/219
21+
var (
22+
_ tfprotov5.FunctionServer = &muxServer{}
23+
//nolint:staticcheck // Intentional verification of interface implementation.
24+
_ tfprotov5.ResourceServerWithMoveResourceState = &muxServer{}
25+
)
26+
1827
// muxServer is a gRPC server implementation that stands in front of other
1928
// gRPC servers, routing requests to them as if they were a single server. It
2029
// should always be instantiated by calling NewMuxServer().

0 commit comments

Comments
 (0)