Skip to content

Commit ff407da

Browse files
committed
Implement ListResource RPC in proto6server
1 parent b706fbc commit ff407da

File tree

6 files changed

+487
-7
lines changed

6 files changed

+487
-7
lines changed

internal/fwserver/server_listresource.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type ListRequest struct {
2323
// Config is the configuration the user supplied for listing resource
2424
// instances.
2525
Config tfsdk.Config
26+
// TODO: Config *tfsdk.Config
2627

2728
// IncludeResource indicates whether the provider should populate the
2829
// Resource field in the ListResult struct.

internal/fwserver/server_listresources.go

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,29 @@ import (
1515
"github.com/hashicorp/terraform-plugin-framework/resource"
1616
)
1717

18+
type ListResourceTypeNotFoundError struct {
19+
TypeName string
20+
}
21+
22+
func (e *ListResourceTypeNotFoundError) Error() string {
23+
return "listResource Type Not Found: no listResource type named " + e.TypeName + " was found in the provider."
24+
}
25+
26+
func (e *ListResourceTypeNotFoundError) Is(err error) bool {
27+
compatibleErr, ok := err.(*ListResourceTypeNotFoundError)
28+
if !ok {
29+
return false
30+
}
31+
32+
return e.TypeName == compatibleErr.TypeName
33+
}
34+
1835
func (s *Server) ListResourceOrError(ctx context.Context, typeName string) (list.ListResource, error) {
1936
listResourceFuncs, _ := s.ListResourceFuncs(ctx)
2037
listResourceFunc, ok := listResourceFuncs[typeName]
2138

2239
if !ok {
23-
return nil, fmt.Errorf("listResource Type Not Found: No listResource type named %q was found in the provider.", typeName)
40+
return nil, &ListResourceTypeNotFoundError{typeName}
2441
}
2542

2643
return listResourceFunc(), nil
@@ -99,17 +116,17 @@ func (s *Server) ListResourceFuncs(ctx context.Context) (map[string]func() list.
99116
// ListResourceMetadatas returns a slice of ListResourceMetadata for the GetMetadata
100117
// RPC.
101118
func (s *Server) ListResourceMetadatas(ctx context.Context) ([]ListResourceMetadata, diag.Diagnostics) {
102-
resourceFuncs, diags := s.ListResourceFuncs(ctx)
119+
listResourceFuncs, diags := s.ListResourceFuncs(ctx)
103120

104-
resourceMetadatas := make([]ListResourceMetadata, 0, len(resourceFuncs))
121+
listResourceMetadatas := make([]ListResourceMetadata, 0, len(listResourceFuncs))
105122

106-
for typeName := range resourceFuncs {
107-
resourceMetadatas = append(resourceMetadatas, ListResourceMetadata{
123+
for typeName := range listResourceFuncs {
124+
listResourceMetadatas = append(listResourceMetadatas, ListResourceMetadata{
108125
TypeName: typeName,
109126
})
110127
}
111128

112-
return resourceMetadatas, diags
129+
return listResourceMetadatas, diags
113130
}
114131

115132
func (s *Server) ListResourceSchema(ctx context.Context, typeName string) (fwschema.Schema, diag.Diagnostics) {
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package proto6server
2+
3+
import (
4+
"context"
5+
6+
"github.com/hashicorp/terraform-plugin-framework/diag"
7+
"github.com/hashicorp/terraform-plugin-framework/internal/fromproto6"
8+
"github.com/hashicorp/terraform-plugin-framework/internal/fwserver"
9+
"github.com/hashicorp/terraform-plugin-framework/internal/toproto6"
10+
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
11+
)
12+
13+
type ResourceSchemaNotFoundError struct {
14+
TypeName string
15+
}
16+
17+
func (e *ResourceSchemaNotFoundError) Error() string {
18+
return "resource schema not found for type: " + e.TypeName
19+
}
20+
func (e *ResourceSchemaNotFoundError) Is(err error) bool {
21+
compatibleErr, ok := err.(*ResourceSchemaNotFoundError)
22+
if !ok {
23+
return false
24+
}
25+
26+
return e.TypeName == compatibleErr.TypeName
27+
}
28+
29+
type ResourceIdentitySchemaNotFoundError struct {
30+
TypeName string
31+
}
32+
33+
func (e *ResourceIdentitySchemaNotFoundError) Error() string {
34+
return "resource identity schema not found for type: " + e.TypeName
35+
}
36+
37+
func (e *ResourceIdentitySchemaNotFoundError) Is(err error) bool {
38+
compatibleErr, ok := err.(*ResourceIdentitySchemaNotFoundError)
39+
if !ok {
40+
return false
41+
}
42+
43+
return e.TypeName == compatibleErr.TypeName
44+
}
45+
46+
type ListResourceSchemaNotFoundError struct {
47+
TypeName string
48+
}
49+
50+
func (e *ListResourceSchemaNotFoundError) Error() string {
51+
return "list resource schema not found for type: " + e.TypeName
52+
}
53+
func (e *ListResourceSchemaNotFoundError) Is(err error) bool {
54+
compatibleErr, ok := err.(*ListResourceSchemaNotFoundError)
55+
if !ok {
56+
return false
57+
}
58+
59+
return e.TypeName == compatibleErr.TypeName
60+
}
61+
62+
type ListResourceConfigError struct {
63+
TypeName string
64+
Diagnostics diag.Diagnostics
65+
}
66+
67+
func (e *ListResourceConfigError) Error() string {
68+
return "list resource config error for type: " + e.TypeName // + ": " + e.Diagnostics.Error()
69+
}
70+
71+
func (e *ListResourceConfigError) Is(err error) bool {
72+
compatibleErr, ok := err.(*ListResourceConfigError)
73+
if !ok {
74+
return false
75+
}
76+
77+
return e.TypeName != compatibleErr.TypeName
78+
}
79+
80+
func (s *Server) ListResource(ctx context.Context, proto6Req *tfprotov6.ListResourceRequest) (*tfprotov6.ListResourceServerStream, error) {
81+
listResource, err := s.FrameworkServer.ListResourceOrError(ctx, proto6Req.TypeName)
82+
if err != nil {
83+
proto6Stream := &tfprotov6.ListResourceServerStream{}
84+
proto6Stream.Results = func(func(tfprotov6.ListResourceResult) bool) {}
85+
86+
return proto6Stream, err
87+
}
88+
89+
resourceSchema, diags := s.FrameworkServer.ResourceSchema(ctx, proto6Req.TypeName)
90+
if diags.HasError() {
91+
proto6Stream := &tfprotov6.ListResourceServerStream{}
92+
proto6Stream.Results = func(func(tfprotov6.ListResourceResult) bool) {}
93+
return proto6Stream, &ResourceSchemaNotFoundError{TypeName: proto6Req.TypeName}
94+
}
95+
96+
identitySchema, diags := s.FrameworkServer.ResourceIdentitySchema(ctx, proto6Req.TypeName)
97+
if diags.HasError() {
98+
proto6Stream := &tfprotov6.ListResourceServerStream{}
99+
proto6Stream.Results = func(func(tfprotov6.ListResourceResult) bool) {}
100+
return proto6Stream, &ResourceIdentitySchemaNotFoundError{TypeName: proto6Req.TypeName} // TODO: return a diagnostic instead of an error?
101+
}
102+
103+
listResourceSchema, diags := s.FrameworkServer.ListResourceSchema(ctx, proto6Req.TypeName)
104+
if diags.HasError() {
105+
proto6Stream := &tfprotov6.ListResourceServerStream{}
106+
proto6Stream.Results = func(func(tfprotov6.ListResourceResult) bool) {}
107+
return proto6Stream, &ListResourceSchemaNotFoundError{TypeName: proto6Req.TypeName}
108+
}
109+
110+
config, diags := fromproto6.Config(ctx, proto6Req.Config, listResourceSchema)
111+
if diags.HasError() {
112+
proto6Stream := &tfprotov6.ListResourceServerStream{}
113+
proto6Stream.Results = func(func(tfprotov6.ListResourceResult) bool) {}
114+
return proto6Stream, &ListResourceConfigError{TypeName: proto6Req.TypeName, Diagnostics: diags}
115+
}
116+
117+
req := &fwserver.ListRequest{
118+
Config: *config,
119+
ListResource: listResource,
120+
ResourceSchema: resourceSchema,
121+
ResourceIdentitySchema: identitySchema,
122+
IncludeResource: proto6Req.IncludeResource,
123+
}
124+
stream := &fwserver.ListResultsStream{}
125+
126+
err = s.FrameworkServer.ListResource(ctx, req, stream)
127+
if err != nil {
128+
return nil, err
129+
}
130+
131+
proto6Stream := &tfprotov6.ListResourceServerStream{}
132+
proto6Stream.Results = func(push func(tfprotov6.ListResourceResult) bool) {
133+
for result := range stream.Results {
134+
var proto6Result tfprotov6.ListResourceResult
135+
if req.IncludeResource {
136+
proto6Result = toproto6.ListResourceResultWithResource(ctx, &result)
137+
} else {
138+
proto6Result = toproto6.ListResourceResult(ctx, &result)
139+
}
140+
141+
if !push(proto6Result) {
142+
return
143+
}
144+
}
145+
}
146+
return proto6Stream, nil
147+
}

0 commit comments

Comments
 (0)