Skip to content

Commit 6997cf5

Browse files
authored
list: add types for ListResource support (#1150)
* list: add types for ListResource support * refactor: rename ListResourceResponse to ListResourceStream * Resolve TODO comment * Rename ResourceObject to Resource * Rename ListResource method to List
1 parent 80ed136 commit 6997cf5

File tree

8 files changed

+374
-0
lines changed

8 files changed

+374
-0
lines changed

list/config_validator.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package list
5+
6+
import "context"
7+
8+
// ConfigValidator describes reusable ListResource configuration validation
9+
// functionality.
10+
type ConfigValidator interface {
11+
// Description describes the validation in plain text formatting.
12+
//
13+
// This information may be automatically added to list resource plain text
14+
// descriptions by external tooling.
15+
Description(context.Context) string
16+
17+
// MarkdownDescription describes the validation in Markdown formatting.
18+
//
19+
// This information may be automatically added to list resource Markdown
20+
// descriptions by external tooling.
21+
MarkdownDescription(context.Context) string
22+
23+
// ValidateResource performs the validation.
24+
//
25+
// This method name is separate from ConfigValidators in resource and other packages in
26+
// order to allow generic validators.
27+
ValidateListResourceConfig(context.Context, ValidateConfigRequest, *ValidateConfigResponse)
28+
}

list/list_resource.go

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package list
5+
6+
import (
7+
"context"
8+
"iter"
9+
10+
"github.com/hashicorp/terraform-plugin-framework/diag"
11+
"github.com/hashicorp/terraform-plugin-framework/resource"
12+
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
13+
)
14+
15+
// ListResource represents an implementation of listing instances of a managed resource
16+
// This is the core interface for all list resource implementations.
17+
//
18+
// ListResource implementations can optionally implement these additional concepts:
19+
//
20+
// - Configure: Include provider-level data or clients.
21+
// - Validation: Schema-based or entire configuration via
22+
// ListResourceWithConfigValidators or ListResourceWithValidateConfig.
23+
type ListResource interface {
24+
// Metadata should return the full name of the list resource such as
25+
// examplecloud_thing. This name should match the full name of the managed
26+
// resource to be listed; otherwise, the GetMetadata RPC will return an
27+
// error diagnostic.
28+
//
29+
// The method signature is intended to be compatible with the Metadata
30+
// method signature in the Resource interface. One implementation of
31+
// Metadata can satisfy both interfaces.
32+
Metadata(context.Context, resource.MetadataRequest, *resource.MetadataResponse)
33+
34+
// ListResourceConfigSchema should return the schema for list blocks.
35+
ListResourceConfigSchema(context.Context, ListResourceSchemaRequest, *ListResourceSchemaResponse)
36+
37+
// List is called when the provider must list instances of a managed
38+
// resource type that satisfy a user-provided request.
39+
List(context.Context, ListRequest, *ListResultsStream)
40+
}
41+
42+
// ListResourceWithConfigure is an interface type that extends ListResource to include a method
43+
// which the framework will automatically call so provider developers have the
44+
// opportunity to setup any necessary provider-level data or clients.
45+
type ListResourceWithConfigure interface {
46+
ListResource
47+
48+
// Configure enables provider-level data or clients to be set. The method
49+
// signature is intended to be compatible with the Configure method
50+
// signature in the Resource interface. One implementation of Configure can
51+
// satisfy both interfaces.
52+
Configure(context.Context, resource.ConfigureRequest, *resource.ConfigureResponse)
53+
}
54+
55+
// ListResourceWithConfigValidators is an interface type that extends
56+
// ListResource to include declarative validations.
57+
//
58+
// Declaring validation using this methodology simplifies implementation of
59+
// reusable functionality. These also include descriptions, which can be used
60+
// for automating documentation.
61+
//
62+
// Validation will include ListResourceConfigValidators and
63+
// ValidateListResourceConfig, if both are implemented, in addition to any
64+
// Attribute or Type validation.
65+
type ListResourceWithConfigValidators interface {
66+
ListResource
67+
68+
// ListResourceConfigValidators returns a list of functions which will all be performed during validation.
69+
ListResourceConfigValidators(context.Context) []ConfigValidator
70+
}
71+
72+
// ListResourceWithValidateConfig is an interface type that extends ListResource to include
73+
// imperative validation.
74+
//
75+
// Declaring validation using this methodology simplifies one-off
76+
// functionality that typically applies to a single resource. Any documentation
77+
// of this functionality must be manually added into schema descriptions.
78+
//
79+
// Validation will include ListResourceConfigValidators and ValidateListResourceConfig, if both
80+
// are implemented, in addition to any Attribute or Type validation.
81+
type ListResourceWithValidateConfig interface {
82+
ListResource
83+
84+
// ValidateListResourceConfig performs the validation.
85+
ValidateListResourceConfig(context.Context, ValidateConfigRequest, *ValidateConfigResponse)
86+
}
87+
88+
// ListRequest represents a request for the provider to list instances
89+
// of a managed resource type that satisfy a user-defined request. An instance
90+
// of this reqeuest struct is passed as an argument to the provider's
91+
// ListResource function implementation.
92+
type ListRequest struct {
93+
// Config is the configuration the user supplied for listing resource
94+
// instances.
95+
Config tfsdk.Config
96+
97+
// IncludeResource indicates whether the provider should populate the
98+
// Resource field in the ListResult struct.
99+
IncludeResource bool
100+
}
101+
102+
// ListResultsStream represents a streaming response to a ListRequest.
103+
// An instance of this struct is supplied as an argument to the provider's
104+
// ListResource function implementation function. The provider should set a Results
105+
// iterator function that yields zero or more results of type ListResult.
106+
//
107+
// For convenience, a provider implementation may choose to convert a slice of
108+
// results into an iterator using [slices.Values].
109+
//
110+
// [slices.Values]: https://pkg.go.dev/slices#Values
111+
type ListResultsStream struct {
112+
// Results is a function that emits ListResult values via its yield
113+
// function argument.
114+
Results iter.Seq[ListResult]
115+
}
116+
117+
// ListResult represents a listed managed resource instance.
118+
type ListResult struct {
119+
// Identity is the identity of the managed resource instance.
120+
//
121+
// A nil value will raise will raise a diagnostic.
122+
Identity *tfsdk.ResourceIdentity
123+
124+
// Resource is the provider's representation of the attributes of the
125+
// listed managed resource instance.
126+
//
127+
// If ListRequest.IncludeResource is true, a nil value will raise
128+
// a warning diagnostic.
129+
Resource *tfsdk.Resource
130+
131+
// DisplayName is a provider-defined human-readable description of the
132+
// listed managed resource instance, intended for CLI and browser UIs.
133+
DisplayName string
134+
135+
// Diagnostics report errors or warnings related to the listed managed
136+
// resource instance. An empty slice indicates a successful operation with
137+
// no warnings or errors generated.
138+
Diagnostics diag.Diagnostics
139+
}
140+
141+
// ValidateConfigRequest represents a request to validate the configuration of
142+
// a list resource. An instance of this request struct is supplied as an
143+
// argument to the ValidateListResourceConfig receiver method or automatically
144+
// passed through to each ListResourceConfigValidator.
145+
type ValidateConfigRequest struct {
146+
// Config is the configuration the user supplied for the resource.
147+
//
148+
// This configuration may contain unknown values if a user uses
149+
// interpolation or other functionality that would prevent Terraform
150+
// from knowing the value at request time.
151+
Config tfsdk.Config
152+
}
153+
154+
// ValidateConfigResponse represents a response to a ValidateConfigRequest. An
155+
// instance of this response struct is supplied as an argument to the
156+
// list.ValidateListResourceConfig receiver method or automatically passed
157+
// through to each ConfigValidator.
158+
type ValidateConfigResponse struct {
159+
// Diagnostics report errors or warnings related to validating the list
160+
// configuration. An empty slice indicates success, with no warnings
161+
// or errors generated.
162+
Diagnostics diag.Diagnostics
163+
}

list/list_resource_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package list_test
5+
6+
import (
7+
"context"
8+
9+
"github.com/hashicorp/terraform-plugin-framework/list"
10+
"github.com/hashicorp/terraform-plugin-framework/resource"
11+
)
12+
13+
type ComputeInstanceResource struct {
14+
NoOpListResource
15+
NoOpResource
16+
}
17+
18+
type ComputeInstanceWithValidateListResourceConfig struct {
19+
ComputeInstanceResource
20+
}
21+
22+
type ComputeInstanceWithListResourceConfigValidators struct {
23+
ComputeInstanceResource
24+
}
25+
26+
func (c *ComputeInstanceResource) Configure(_ context.Context, _ resource.ConfigureRequest, _ *resource.ConfigureResponse) {
27+
}
28+
29+
func (c *ComputeInstanceResource) Metadata(_ context.Context, _ resource.MetadataRequest, _ *resource.MetadataResponse) {
30+
}
31+
32+
func (c *ComputeInstanceWithValidateListResourceConfig) ValidateListResourceConfig(_ context.Context, _ list.ValidateConfigRequest, _ *list.ValidateConfigResponse) {
33+
}
34+
35+
func (c *ComputeInstanceWithListResourceConfigValidators) ListResourceConfigValidators(_ context.Context) []list.ConfigValidator {
36+
return nil
37+
}
38+
39+
// ExampleResource_listable demonstrates a resource.Resource that implements
40+
// list.ListResource interfaces.
41+
func ExampleResource_listable() {
42+
var _ list.ListResource = &ComputeInstanceResource{}
43+
var _ list.ListResourceWithConfigure = &ComputeInstanceResource{}
44+
var _ list.ListResourceWithValidateConfig = &ComputeInstanceWithValidateListResourceConfig{}
45+
var _ list.ListResourceWithConfigValidators = &ComputeInstanceWithListResourceConfigValidators{}
46+
47+
var _ resource.Resource = &ComputeInstanceResource{}
48+
var _ resource.ResourceWithConfigure = &ComputeInstanceResource{}
49+
50+
// Output:
51+
}

list/no_op_list_resource_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package list_test
5+
6+
import (
7+
"context"
8+
9+
"github.com/hashicorp/terraform-plugin-framework/list"
10+
)
11+
12+
type NoOpListResource struct{}
13+
14+
func (*NoOpListResource) ListResourceConfigSchema(_ context.Context, _ list.ListResourceSchemaRequest, _ *list.ListResourceSchemaResponse) {
15+
}
16+
17+
func (*NoOpListResource) List(_ context.Context, _ list.ListRequest, _ *list.ListResultsStream) {
18+
}

list/no_op_resource_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package list_test
5+
6+
import (
7+
"context"
8+
9+
"github.com/hashicorp/terraform-plugin-framework/resource"
10+
)
11+
12+
type NoOpResource struct{}
13+
14+
func (*NoOpResource) Schema(_ context.Context, _ resource.SchemaRequest, _ *resource.SchemaResponse) {
15+
}
16+
17+
func (*NoOpResource) Create(_ context.Context, _ resource.CreateRequest, _ *resource.CreateResponse) {
18+
}
19+
20+
func (*NoOpResource) Read(_ context.Context, _ resource.ReadRequest, _ *resource.ReadResponse) {
21+
}
22+
23+
func (*NoOpResource) Update(_ context.Context, _ resource.UpdateRequest, _ *resource.UpdateResponse) {
24+
}
25+
26+
func (*NoOpResource) Delete(_ context.Context, _ resource.DeleteRequest, _ *resource.DeleteResponse) {
27+
}

list/schema.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package list
5+
6+
import (
7+
"github.com/hashicorp/terraform-plugin-framework/diag"
8+
"github.com/hashicorp/terraform-plugin-framework/list/schema"
9+
)
10+
11+
// ListResourceSchemaRequest represents a request for the ListResource to
12+
// return its schema. An instance of this request struct is supplied as an
13+
// argument to the ListResource type ListResourceSchema method.
14+
type ListResourceSchemaRequest struct{}
15+
16+
// ListResourceSchemaResponse represents a response to a
17+
// ListResourceSchemaRequest. An instance of this response struct is supplied
18+
// as an argument to the ListResource type ListResourceResourceSchema method.
19+
type ListResourceSchemaResponse struct {
20+
// Schema is the schema of the list resource.
21+
Schema schema.Schema
22+
23+
// Diagnostics report errors or warnings related to retrieving the list
24+
// resource schema. An empty slice indicates success, with no warnings
25+
// or errors generated.
26+
Diagnostics diag.Diagnostics
27+
}

list/schema/schema.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package schema
5+
6+
type Schema struct {
7+
}

tfsdk/resource.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package tfsdk
5+
6+
import (
7+
"context"
8+
9+
"github.com/hashicorp/terraform-plugin-framework/diag"
10+
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
11+
"github.com/hashicorp/terraform-plugin-framework/internal/fwschemadata"
12+
"github.com/hashicorp/terraform-plugin-framework/path"
13+
"github.com/hashicorp/terraform-plugin-go/tftypes"
14+
)
15+
16+
// Resource represents a Terraform resource.
17+
type Resource struct {
18+
Raw tftypes.Value
19+
Schema fwschema.Schema
20+
}
21+
22+
// Get populates the struct passed as `target` with the resource.
23+
func (c Resource) Get(ctx context.Context, target interface{}) diag.Diagnostics {
24+
return c.data().Get(ctx, target)
25+
}
26+
27+
// GetAttribute retrieves the attribute or block found at `path` and populates
28+
// the `target` with the value. This method is intended for top level schema
29+
// attributes or blocks. Use `types` package methods or custom types to step
30+
// into collections.
31+
//
32+
// Attributes or elements under null or unknown collections return null
33+
// values, however this behavior is not protected by compatibility promises.
34+
func (c Resource) GetAttribute(ctx context.Context, path path.Path, target interface{}) diag.Diagnostics {
35+
return c.data().GetAtPath(ctx, path, target)
36+
}
37+
38+
// PathMatches returns all matching path.Paths from the given path.Expression.
39+
//
40+
// If a parent path is null or unknown, which would prevent a full expression
41+
// from matching, the parent path is returned rather than no match to prevent
42+
// false positives.
43+
func (c Resource) PathMatches(ctx context.Context, pathExpr path.Expression) (path.Paths, diag.Diagnostics) {
44+
return c.data().PathMatches(ctx, pathExpr)
45+
}
46+
47+
func (c Resource) data() fwschemadata.Data {
48+
return fwschemadata.Data{
49+
Description: fwschemadata.DataDescriptionConfiguration,
50+
Schema: c.Schema,
51+
TerraformValue: c.Raw,
52+
}
53+
}

0 commit comments

Comments
 (0)