-
Notifications
You must be signed in to change notification settings - Fork 97
Add ListResource RPC #1157
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ListResource RPC #1157
Conversation
6414d9d
to
ed02781
Compare
56424fa
to
d5d9cb5
Compare
af2d8f7
to
380b706
Compare
380b706
to
ce0467f
Compare
@@ -68,7 +80,8 @@ func (s *Server) ListResourceFuncs(ctx context.Context) (map[string]func() list. | |||
continue | |||
} | |||
|
|||
if _, ok := s.resourceFuncs[typeName]; !ok { | |||
resourceFuncs, _ := s.ResourceFuncs(ctx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cross-ref: #1152 (comment)
This feels more robust. And removes the need for "call X before Y" comments.
Results iter.Seq[ListResult] | ||
} | ||
|
||
func ListResultError(summary string, detail string) ListResult { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: add a doc comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it's not a "publicly" exported field, no need to add a doc comment unless you feel this helper needs more explanation for maintainers.
Although I'm wondering if this function even needs to be exported (or even exist, it's only used once ATM, maybe it will be used more later?)
@@ -69,7 +85,8 @@ func (s *Server) ListResourceFuncs(ctx context.Context) (map[string]func() list. | |||
continue | |||
} | |||
|
|||
if _, ok := s.resourceFuncs[typeName]; !ok { | |||
resourceFuncs, _ := s.ResourceFuncs(ctx) | |||
if _, ok := resourceFuncs[typeName]; !ok { | |||
s.listResourceFuncsDiags.AddError( | |||
"ListResource Type Defined without a Matching Managed Resource Type", | |||
fmt.Sprintf("The %s ListResource type name was returned, but no matching managed Resource type was defined. ", typeName)+ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO, after this PR: we want the flexibility for a list resource in Framework to work with a managed resource type in SDKv2. So we'll revisit this logic.
return ListRequestErrorDiagnostics(ctx, allDiags...) | ||
} | ||
|
||
resourceSchema, diags := s.FrameworkServer.ResourceSchema(ctx, protoReq.TypeName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO, after this PR: we want the flexibility for a list resource in Framework to work with a managed resource type in SDKv2. So we'll revisit this logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I'd think since fwserver
doesn't need these values, then this would just be something could be a nil
all the way through to the List
call. Where the provider developer would then just construct tfsdk.Resource
themselves? (which needs to happen anyways?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is the fun part. As in #1157 (comment), good enough for this PR while under construction for SDKv2 considerations.
As I piece this together, I see that a provider developer typically writes:
resp.State.Set(ctx, &data)
and this works because fwserver has pre-set resp.State.Schema
:
terraform-plugin-framework/internal/fwserver/server_readresource.go
Lines 99 to 104 in a7f8748
readResp := resource.ReadResponse{ | |
State: tfsdk.State{ | |
Schema: req.CurrentState.Schema, | |
Raw: req.CurrentState.Raw.Copy(), | |
}, | |
} |
This is the one reason that fwserver.ListResource
is interested in the resource schema and resource identity schema.
And then the "pre-set" mechanics are a little different from resp.State
because List
returns multiple entities instead of a single entity, as you've referred to in #1157 (comment). We definitely have room to improve on that.
In the next form of this, I'm hoping we can unexport the *Schema
struct fields ✅
return ListRequestErrorDiagnostics(ctx, allDiags...) | ||
} | ||
|
||
identitySchema, diags := s.FrameworkServer.ResourceIdentitySchema(ctx, protoReq.TypeName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO, after this PR: we want the flexibility for a list resource in Framework to work with a managed resource type in SDKv2. So we'll revisit this logic.
return identity, diags | ||
} | ||
|
||
func (r ListRequest) ToListResult(ctx context.Context, identityVal any, resourceVal any, displayName string) ListResult { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO, after this PR: we want the flexibility for a list resource in Framework to work with a managed resource type in SDKv2. So we'll revisit this helper method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall this LGTM, I left some general comments and thoughts
if fwReq.Config == nil { | ||
return errors.New("Invalid ListResource request: Config cannot be nil") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason we aren't using response diagnostics here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no functional reason. I was on the fence re: error
or diagnostics. I learned that Terraform can work with either one, so error
struck me as simpler for a request-level nil check.
Now that we have a 👍 on "push a single event with an error diagnostic," we could totally use diagnostics instead. I'm open to that. Any preference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of framework (like the type system for example) uses diagnostics, which are just a summary/detail, so I'd say we should stick to diagnostics unless we can't for whatever reason 👍🏻
return ListResult(result) | ||
} | ||
|
||
if result.Identity == nil { // TODO: is result.Identity.Raw.IsNull() a practical concern? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the question would: does Terraform core care if the provider returns a null
identity? I would say we probably shouldn't return a null
identity unless core says that's acceptable.
In which case we should just check both:
result.Identity == nil
being the provider likely didn't set anythingresult.Identity.Raw.IsNull()
being the provider explicitly set a null value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Terraform currently raises an error when a list result has no identity
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably the area we'd want the most feedback on from provider developers right? One thought might be to store the identity/resource schemas on ListResultsStream
rather then on the request (also do they need to be exported? 🤔 )
Would a variant of this for multiple list results also we worth doing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For example, today we have a lot of resp.Set
which internally use schema data, maybe this would end up being a result.Append
variation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ready for re-review and auto-merge. TODO items for follow-up:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 🚀
Description
This change adds the ListResource RPC.
This is ~80% ready, so I feel okay moving it out of draft mode. I plan to make a round of code review comments, as a guided walkthrough.
Rollback Plan
Changes to Security Controls
None