Skip to content

Commit ce3e07c

Browse files
authored
Initial Setup for ValidateListResourceConfig in List RPCs (#514)
* Add protobuf support for list messages and rpcs * Add ValidateListResourceConfig rpc * Update protobuf to reflect core changes * Add ValidateListResourceConig to server.go * Add temporary interface ProviderServerWithListResource for List * Checking file format * Addressing PR comments
1 parent 553984c commit ce3e07c

File tree

20 files changed

+788
-8
lines changed

20 files changed

+788
-8
lines changed

internal/logging/context.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,15 @@ func EphemeralResourceContext(ctx context.Context, ephemeralResource string) con
9191
return ctx
9292
}
9393

94+
// ListResourceContext injects the list resource type into logger contexts.
95+
func ListResourceContext(ctx context.Context, listResource string) context.Context {
96+
ctx = tfsdklog.SetField(ctx, KeyListResourceType, listResource)
97+
ctx = tfsdklog.SubsystemSetField(ctx, SubsystemProto, KeyListResourceType, listResource)
98+
ctx = tflog.SetField(ctx, KeyListResourceType, listResource)
99+
100+
return ctx
101+
}
102+
94103
// RpcContext injects the RPC name into logger contexts.
95104
func RpcContext(ctx context.Context, rpc string) context.Context {
96105
ctx = tfsdklog.SetField(ctx, KeyRPC, rpc)

internal/logging/keys.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ const (
6060
// The type of ephemeral resource being operated on, such as "random_password"
6161
KeyEphemeralResourceType = "tf_ephemeral_resource_type"
6262

63+
// The type of list resource being operated on
64+
KeyListResourceType = "tf_list_resource_type"
65+
6366
// Path to protocol data file, such as "/tmp/example.json"
6467
KeyProtocolDataFile = "tf_proto_data_file"
6568

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package fromproto
5+
6+
import (
7+
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
8+
"github.com/hashicorp/terraform-plugin-go/tfprotov5/internal/tfplugin5"
9+
)
10+
11+
func ValidateListResourceConfigRequest(in *tfplugin5.ValidateListResourceConfig_Request) *tfprotov5.ValidateListResourceConfigRequest {
12+
if in == nil {
13+
return nil
14+
}
15+
16+
return &tfprotov5.ValidateListResourceConfigRequest{
17+
TypeName: in.TypeName,
18+
Config: DynamicValue(in.Config),
19+
}
20+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package fromproto_test
5+
6+
import (
7+
"testing"
8+
9+
"github.com/google/go-cmp/cmp"
10+
11+
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
12+
"github.com/hashicorp/terraform-plugin-go/tfprotov5/internal/fromproto"
13+
"github.com/hashicorp/terraform-plugin-go/tfprotov5/internal/tfplugin5"
14+
)
15+
16+
func TestValidateListResourceConfigRequest(t *testing.T) {
17+
t.Parallel()
18+
19+
testCases := map[string]struct {
20+
in *tfplugin5.ValidateListResourceConfig_Request
21+
expected *tfprotov5.ValidateListResourceConfigRequest
22+
}{
23+
"nil": {
24+
in: nil,
25+
expected: nil,
26+
},
27+
"zero": {
28+
in: &tfplugin5.ValidateListResourceConfig_Request{},
29+
expected: &tfprotov5.ValidateListResourceConfigRequest{},
30+
},
31+
"Config": {
32+
in: &tfplugin5.ValidateListResourceConfig_Request{
33+
Config: testTfplugin5DynamicValue(),
34+
},
35+
expected: &tfprotov5.ValidateListResourceConfigRequest{
36+
Config: testTfprotov5DynamicValue(),
37+
},
38+
},
39+
"TypeName": {
40+
in: &tfplugin5.ValidateListResourceConfig_Request{
41+
TypeName: "test",
42+
},
43+
expected: &tfprotov5.ValidateListResourceConfigRequest{
44+
TypeName: "test",
45+
},
46+
},
47+
}
48+
49+
for name, testCase := range testCases {
50+
t.Run(name, func(t *testing.T) {
51+
t.Parallel()
52+
53+
got := fromproto.ValidateListResourceConfigRequest(testCase.in)
54+
55+
if diff := cmp.Diff(got, testCase.expected); diff != "" {
56+
t.Errorf("unexpected difference: %s", diff)
57+
}
58+
})
59+
}
60+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package toproto
5+
6+
import (
7+
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
8+
"github.com/hashicorp/terraform-plugin-go/tfprotov5/internal/tfplugin5"
9+
)
10+
11+
func GetMetadata_ListResourceMetadata(in *tfprotov5.ListResourceMetadata) *tfplugin5.GetMetadata_ListResourceMetadata {
12+
if in == nil {
13+
return nil
14+
}
15+
16+
return &tfplugin5.GetMetadata_ListResourceMetadata{
17+
TypeName: in.TypeName,
18+
}
19+
}
20+
21+
func ValidateListResourceConfig_Response(in *tfprotov5.ValidateListResourceConfigResponse) *tfplugin5.ValidateListResourceConfig_Response {
22+
if in == nil {
23+
return nil
24+
}
25+
26+
return &tfplugin5.ValidateListResourceConfig_Response{
27+
Diagnostics: Diagnostics(in.Diagnostics),
28+
}
29+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package toproto_test
5+
6+
import (
7+
"testing"
8+
9+
"github.com/google/go-cmp/cmp"
10+
"github.com/google/go-cmp/cmp/cmpopts"
11+
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
12+
"github.com/hashicorp/terraform-plugin-go/tfprotov5/internal/tfplugin5"
13+
"github.com/hashicorp/terraform-plugin-go/tfprotov5/internal/toproto"
14+
)
15+
16+
func TestGetMetadata_ListResourceMetadata(t *testing.T) {
17+
t.Parallel()
18+
19+
testCases := map[string]struct {
20+
in *tfprotov5.ListResourceMetadata
21+
expected *tfplugin5.GetMetadata_ListResourceMetadata
22+
}{
23+
"nil": {
24+
in: nil,
25+
expected: nil,
26+
},
27+
"zero": {
28+
in: &tfprotov5.ListResourceMetadata{},
29+
expected: &tfplugin5.GetMetadata_ListResourceMetadata{},
30+
},
31+
"TypeName": {
32+
in: &tfprotov5.ListResourceMetadata{
33+
TypeName: "test",
34+
},
35+
expected: &tfplugin5.GetMetadata_ListResourceMetadata{
36+
TypeName: "test",
37+
},
38+
},
39+
}
40+
41+
for name, testCase := range testCases {
42+
t.Run(name, func(t *testing.T) {
43+
t.Parallel()
44+
45+
got := toproto.GetMetadata_ListResourceMetadata(testCase.in)
46+
47+
// Protocol Buffers generated types must have unexported fields
48+
// ignored or cmp.Diff() will raise an error. This is easier than
49+
// writing a custom Comparer for each type, which would have no
50+
// benefits.
51+
diffOpts := cmpopts.IgnoreUnexported(
52+
tfplugin5.GetMetadata_ListResourceMetadata{},
53+
)
54+
55+
if diff := cmp.Diff(got, testCase.expected, diffOpts); diff != "" {
56+
t.Errorf("unexpected difference: %s", diff)
57+
}
58+
})
59+
}
60+
}
61+
62+
func TestValidateListResourceConfig_Response(t *testing.T) {
63+
t.Parallel()
64+
65+
testCases := map[string]struct {
66+
in *tfprotov5.ValidateListResourceConfigResponse
67+
expected *tfplugin5.ValidateListResourceConfig_Response
68+
}{
69+
"nil": {
70+
in: nil,
71+
expected: nil,
72+
},
73+
"zero": {
74+
in: &tfprotov5.ValidateListResourceConfigResponse{},
75+
expected: &tfplugin5.ValidateListResourceConfig_Response{
76+
Diagnostics: []*tfplugin5.Diagnostic{},
77+
},
78+
},
79+
"Diagnostics": {
80+
in: &tfprotov5.ValidateListResourceConfigResponse{
81+
Diagnostics: []*tfprotov5.Diagnostic{
82+
testTfprotov5Diagnostic,
83+
},
84+
},
85+
expected: &tfplugin5.ValidateListResourceConfig_Response{
86+
Diagnostics: []*tfplugin5.Diagnostic{
87+
testTfplugin5Diagnostic,
88+
},
89+
},
90+
},
91+
}
92+
93+
for name, testCase := range testCases {
94+
t.Run(name, func(t *testing.T) {
95+
t.Parallel()
96+
97+
got := toproto.ValidateListResourceConfig_Response(testCase.in)
98+
99+
// Protocol Buffers generated types must have unexported fields
100+
// ignored or cmp.Diff() will raise an error. This is easier than
101+
// writing a custom Comparer for each type, which would have no
102+
// benefits.
103+
diffOpts := cmpopts.IgnoreUnexported(
104+
tfplugin5.Diagnostic{},
105+
tfplugin5.ValidateListResourceConfig_Response{},
106+
)
107+
108+
if diff := cmp.Diff(got, testCase.expected, diffOpts); diff != "" {
109+
t.Errorf("unexpected difference: %s", diff)
110+
}
111+
})
112+
}
113+
}

tfprotov5/internal/toproto/provider.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ func GetMetadata_Response(in *tfprotov5.GetMetadataResponse) *tfplugin5.GetMetad
1717
DataSources: make([]*tfplugin5.GetMetadata_DataSourceMetadata, 0, len(in.DataSources)),
1818
Diagnostics: Diagnostics(in.Diagnostics),
1919
EphemeralResources: make([]*tfplugin5.GetMetadata_EphemeralResourceMetadata, 0, len(in.EphemeralResources)),
20+
ListResources: make([]*tfplugin5.GetMetadata_ListResourceMetadata, 0, len(in.ListResources)),
2021
Functions: make([]*tfplugin5.GetMetadata_FunctionMetadata, 0, len(in.Functions)),
2122
Resources: make([]*tfplugin5.GetMetadata_ResourceMetadata, 0, len(in.Resources)),
2223
ServerCapabilities: ServerCapabilities(in.ServerCapabilities),
@@ -30,6 +31,10 @@ func GetMetadata_Response(in *tfprotov5.GetMetadataResponse) *tfplugin5.GetMetad
3031
resp.EphemeralResources = append(resp.EphemeralResources, GetMetadata_EphemeralResourceMetadata(&ephemeralResource))
3132
}
3233

34+
for _, listResource := range in.ListResources {
35+
resp.ListResources = append(resp.ListResources, GetMetadata_ListResourceMetadata(&listResource))
36+
}
37+
3338
for _, function := range in.Functions {
3439
resp.Functions = append(resp.Functions, GetMetadata_FunctionMetadata(&function))
3540
}
@@ -50,6 +55,7 @@ func GetProviderSchema_Response(in *tfprotov5.GetProviderSchemaResponse) *tfplug
5055
DataSourceSchemas: make(map[string]*tfplugin5.Schema, len(in.DataSourceSchemas)),
5156
Diagnostics: Diagnostics(in.Diagnostics),
5257
EphemeralResourceSchemas: make(map[string]*tfplugin5.Schema, len(in.EphemeralResourceSchemas)),
58+
ListResourceSchemas: make(map[string]*tfplugin5.Schema, len(in.ListResourceSchemas)),
5359
Functions: make(map[string]*tfplugin5.Function, len(in.Functions)),
5460
Provider: Schema(in.Provider),
5561
ProviderMeta: Schema(in.ProviderMeta),
@@ -61,6 +67,10 @@ func GetProviderSchema_Response(in *tfprotov5.GetProviderSchemaResponse) *tfplug
6167
resp.EphemeralResourceSchemas[name] = Schema(schema)
6268
}
6369

70+
for name, schema := range in.ListResourceSchemas {
71+
resp.ListResourceSchemas[name] = Schema(schema)
72+
}
73+
6474
for name, schema := range in.ResourceSchemas {
6575
resp.ResourceSchemas[name] = Schema(schema)
6676
}

0 commit comments

Comments
 (0)