Skip to content

Commit 8434065

Browse files
committed
provider: Require Metadata method for Provider interface
To remove potential confusion about optionally specifying this information. In the future, the provider metadata can be expanded further for documentation generation purposes.
1 parent ea5dd66 commit 8434065

File tree

11 files changed

+114
-110
lines changed

11 files changed

+114
-110
lines changed

.changelog/pending.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:breaking-change
2+
provider: The `Provider` interface now requires the `Metadata` method. It can be left empty or set the `MetadataResponse` type `TypeName` field to populate `datasource.MetadataRequest` and `resource.MetadataRequest` type `ProviderTypeName` fields.
3+
```

internal/fwserver/server_getproviderschema.go

+6-10
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,14 @@ func (s *Server) GetProviderSchema(ctx context.Context, req *GetProviderSchemaRe
3030
PlanDestroy: true,
3131
}
3232

33-
if providerWithMetadata, ok := s.Provider.(provider.ProviderWithMetadata); ok {
34-
logging.FrameworkTrace(ctx, "Provider implements ProviderWithMetadata")
33+
metadataReq := provider.MetadataRequest{}
34+
metadataResp := provider.MetadataResponse{}
3535

36-
metadataReq := provider.MetadataRequest{}
37-
metadataResp := provider.MetadataResponse{}
36+
logging.FrameworkDebug(ctx, "Calling provider defined Provider Metadata")
37+
s.Provider.Metadata(ctx, metadataReq, &metadataResp)
38+
logging.FrameworkDebug(ctx, "Called provider defined Provider Metadata")
3839

39-
logging.FrameworkDebug(ctx, "Calling provider defined Provider Metadata")
40-
providerWithMetadata.Metadata(ctx, metadataReq, &metadataResp)
41-
logging.FrameworkDebug(ctx, "Called provider defined Provider Metadata")
42-
43-
s.providerTypeName = metadataResp.TypeName
44-
}
40+
s.providerTypeName = metadataResp.TypeName
4541

4642
providerSchema, diags := s.ProviderSchema(ctx)
4743

internal/fwserver/server_getproviderschema_test.go

+38-42
Original file line numberDiff line numberDiff line change
@@ -258,31 +258,29 @@ func TestServerGetProviderSchema(t *testing.T) {
258258
},
259259
"datasourceschemas-provider-type-name": {
260260
server: &fwserver.Server{
261-
Provider: &testprovider.ProviderWithMetadata{
261+
Provider: &testprovider.Provider{
262262
MetadataMethod: func(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
263263
resp.TypeName = "testprovidertype"
264264
},
265-
Provider: &testprovider.Provider{
266-
DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource {
267-
return []func() datasource.DataSource{
268-
func() datasource.DataSource {
269-
return &testprovider.DataSource{
270-
SchemaMethod: func(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
271-
resp.Schema = datasourceschema.Schema{
272-
Attributes: map[string]datasourceschema.Attribute{
273-
"test": datasourceschema.StringAttribute{
274-
Required: true,
275-
},
265+
DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource {
266+
return []func() datasource.DataSource{
267+
func() datasource.DataSource {
268+
return &testprovider.DataSource{
269+
SchemaMethod: func(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
270+
resp.Schema = datasourceschema.Schema{
271+
Attributes: map[string]datasourceschema.Attribute{
272+
"test": datasourceschema.StringAttribute{
273+
Required: true,
276274
},
277-
}
278-
},
279-
MetadataMethod: func(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
280-
resp.TypeName = req.ProviderTypeName + "_data_source"
281-
},
282-
}
283-
},
284-
}
285-
},
275+
},
276+
}
277+
},
278+
MetadataMethod: func(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
279+
resp.TypeName = req.ProviderTypeName + "_data_source"
280+
},
281+
}
282+
},
283+
}
286284
},
287285
},
288286
},
@@ -640,31 +638,29 @@ func TestServerGetProviderSchema(t *testing.T) {
640638
},
641639
"resourceschemas-provider-type-name": {
642640
server: &fwserver.Server{
643-
Provider: &testprovider.ProviderWithMetadata{
641+
Provider: &testprovider.Provider{
644642
MetadataMethod: func(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
645643
resp.TypeName = "testprovidertype"
646644
},
647-
Provider: &testprovider.Provider{
648-
ResourcesMethod: func(_ context.Context) []func() resource.Resource {
649-
return []func() resource.Resource{
650-
func() resource.Resource {
651-
return &testprovider.Resource{
652-
SchemaMethod: func(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
653-
resp.Schema = resourceschema.Schema{
654-
Attributes: map[string]resourceschema.Attribute{
655-
"test": resourceschema.StringAttribute{
656-
Required: true,
657-
},
645+
ResourcesMethod: func(_ context.Context) []func() resource.Resource {
646+
return []func() resource.Resource{
647+
func() resource.Resource {
648+
return &testprovider.Resource{
649+
SchemaMethod: func(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
650+
resp.Schema = resourceschema.Schema{
651+
Attributes: map[string]resourceschema.Attribute{
652+
"test": resourceschema.StringAttribute{
653+
Required: true,
658654
},
659-
}
660-
},
661-
MetadataMethod: func(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
662-
resp.TypeName = req.ProviderTypeName + "_resource"
663-
},
664-
}
665-
},
666-
}
667-
},
655+
},
656+
}
657+
},
658+
MetadataMethod: func(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
659+
resp.TypeName = req.ProviderTypeName + "_resource"
660+
},
661+
}
662+
},
663+
}
668664
},
669665
},
670666
},

internal/proto5server/server_getproviderschema_test.go

+10
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,16 @@ func TestServerGetProviderSchema_logging(t *testing.T) {
514514
}
515515

516516
expectedEntries := []map[string]interface{}{
517+
{
518+
"@level": "debug",
519+
"@message": "Calling provider defined Provider Metadata",
520+
"@module": "sdk.framework",
521+
},
522+
{
523+
"@level": "debug",
524+
"@message": "Called provider defined Provider Metadata",
525+
"@module": "sdk.framework",
526+
},
517527
{
518528
"@level": "trace",
519529
"@message": "Checking ProviderSchema lock",

internal/proto6server/server_getproviderschema_test.go

+10
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,16 @@ func TestServerGetProviderSchema_logging(t *testing.T) {
514514
}
515515

516516
expectedEntries := []map[string]interface{}{
517+
{
518+
"@level": "debug",
519+
"@message": "Calling provider defined Provider Metadata",
520+
"@module": "sdk.framework",
521+
},
522+
{
523+
"@level": "debug",
524+
"@message": "Called provider defined Provider Metadata",
525+
"@module": "sdk.framework",
526+
},
517527
{
518528
"@level": "trace",
519529
"@message": "Checking ProviderSchema lock",

internal/testing/testprovider/provider.go

+16-10
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,14 @@ var _ provider.Provider = &Provider{}
1313
// Declarative provider.Provider for unit testing.
1414
type Provider struct {
1515
// Provider interface methods
16-
ConfigureMethod func(context.Context, provider.ConfigureRequest, *provider.ConfigureResponse)
17-
SchemaMethod func(context.Context, provider.SchemaRequest, *provider.SchemaResponse)
18-
19-
// ProviderWithDataSources interface methods
16+
MetadataMethod func(context.Context, provider.MetadataRequest, *provider.MetadataResponse)
17+
ConfigureMethod func(context.Context, provider.ConfigureRequest, *provider.ConfigureResponse)
18+
SchemaMethod func(context.Context, provider.SchemaRequest, *provider.SchemaResponse)
2019
DataSourcesMethod func(context.Context) []func() datasource.DataSource
21-
22-
// ProviderWithResources interface methods
23-
ResourcesMethod func(context.Context) []func() resource.Resource
20+
ResourcesMethod func(context.Context) []func() resource.Resource
2421
}
2522

26-
// GetSchema satisfies the provider.Provider interface.
23+
// Configure satisfies the provider.Provider interface.
2724
func (p *Provider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
2825
if p == nil || p.ConfigureMethod == nil {
2926
return
@@ -32,7 +29,7 @@ func (p *Provider) Configure(ctx context.Context, req provider.ConfigureRequest,
3229
p.ConfigureMethod(ctx, req, resp)
3330
}
3431

35-
// DataSources satisfies the provider.ProviderWithDataSources interface.
32+
// DataSources satisfies the provider.Provider interface.
3633
func (p *Provider) DataSources(ctx context.Context) []func() datasource.DataSource {
3734
if p == nil || p.DataSourcesMethod == nil {
3835
return nil
@@ -41,6 +38,15 @@ func (p *Provider) DataSources(ctx context.Context) []func() datasource.DataSour
4138
return p.DataSourcesMethod(ctx)
4239
}
4340

41+
// Metadata satisfies the provider.Provider interface.
42+
func (p *Provider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
43+
if p == nil || p.MetadataMethod == nil {
44+
return
45+
}
46+
47+
p.MetadataMethod(ctx, req, resp)
48+
}
49+
4450
// Schema satisfies the provider.Provider interface.
4551
func (p *Provider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
4652
if p == nil || p.SchemaMethod == nil {
@@ -50,7 +56,7 @@ func (p *Provider) Schema(ctx context.Context, req provider.SchemaRequest, resp
5056
p.SchemaMethod(ctx, req, resp)
5157
}
5258

53-
// Resources satisfies the provider.ProviderWithResources interface.
59+
// Resources satisfies the provider.Provider interface.
5460
func (p *Provider) Resources(ctx context.Context) []func() resource.Resource {
5561
if p == nil || p.ResourcesMethod == nil {
5662
return nil

internal/testing/testprovider/providerwithmetadata.go

-27
This file was deleted.

provider/provider.go

+8-15
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ import (
1515
// via ProviderWithConfigValidators or ProviderWithValidateConfig.
1616
// - Meta Schema: ProviderWithMetaSchema
1717
type Provider interface {
18+
// Metadata should return the metadata for the provider, such as
19+
// a type name and version data.
20+
//
21+
// Implementing the MetadataResponse.TypeName will populate the
22+
// datasource.MetadataRequest.ProviderTypeName and
23+
// resource.MetadataRequest.ProviderTypeName fields automatically.
24+
Metadata(context.Context, MetadataRequest, *MetadataResponse)
25+
1826
// Schema should return the schema for this provider.
1927
Schema(context.Context, SchemaRequest, *SchemaResponse)
2028

@@ -57,21 +65,6 @@ type ProviderWithConfigValidators interface {
5765
ConfigValidators(context.Context) []ConfigValidator
5866
}
5967

60-
// ProviderWithMetadata is an interface type that extends Provider to
61-
// return its type name, such as examplecloud, and other
62-
// metadata, such as version.
63-
//
64-
// Implementing this method will populate the
65-
// [datasource.MetadataRequest.ProviderTypeName] and
66-
// [resource.MetadataRequest.ProviderTypeName] fields automatically.
67-
type ProviderWithMetadata interface {
68-
Provider
69-
70-
// Metadata should return the metadata for the provider, such as
71-
// a type name and version data.
72-
Metadata(context.Context, MetadataRequest, *MetadataResponse)
73-
}
74-
7568
// ProviderWithMetaSchema is a provider with a provider meta schema, which
7669
// is configured by practitioners via the provider_meta configuration block
7770
// and the configuration data is included with certain data source and resource

website/docs/plugin/framework/data-sources/index.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func (d *ThingDataSource) Metadata(ctx context.Context, req datasource.MetadataR
7979
}
8080
```
8181

82-
To simplify data source implementations, the [`provider.MetadataResponse.TypeName` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#MetadataResponse.TypeName) from the [`provider.ProviderWithMetadata` interface `Metadata` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#ProviderWithMetadata.Metadata) can set the provider name so it is available in the [`datasource.MetadataRequest.ProviderTypeName` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/datasource#MetadataRequest.ProviderTypeName).
82+
To simplify data source implementations, the [`provider.MetadataResponse.TypeName` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#MetadataResponse.TypeName) from the [`provider.Provider` interface `Metadata` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#Provider.Metadata) can set the provider name so it is available in the [`datasource.MetadataRequest.ProviderTypeName` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/datasource#MetadataRequest.ProviderTypeName).
8383

8484
In this example, the provider defines the `examplecloud` name for itself, and the data source is named `examplecloud_thing`:
8585

website/docs/plugin/framework/providers/index.mdx

+19-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,12 @@ type ExampleCloudProvider struct{
3535
Version string
3636
}
3737

38-
// GetSchema satisfies the provider.Provider interface for exampleProvider.
38+
// Metadata satisfies the provider.Provider interface for ExampleCloudProvider
39+
func (p *ExampleCloudProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
40+
resp.TypeName = // provider specific implementation
41+
}
42+
43+
// Schema satisfies the provider.Provider interface for ExampleCloudProvider.
3944
func (p *ExampleCloudProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
4045
resp.Schema = schema.Schema{
4146
Attributes: map[string]schema.Attribute{
@@ -76,7 +81,19 @@ func New(version string) func() provider.Provider {
7681
}
7782
```
7883

79-
### GetSchema Method
84+
### Metadata Method
85+
86+
The [`provider.Provider` interface `Metadata` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#Provider.Metadata) defines information about the provider itself, such as its type name and version. This information is used to simplify creating data sources and resources.
87+
88+
In this example, the provider type name is set to `examplecloud`:
89+
90+
```go
91+
func (p *ExampleCloudProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
92+
resp.TypeName = "examplecloud"
93+
}
94+
```
95+
96+
### Schema Method
8097

8198
The [`provider.Provider` interface `Schema` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#Provider.Schema) defines a [schema](/plugin/framework/schemas) describing what data is available in the provider's configuration. This configuration block is used to offer practitioners the opportunity to supply values to the provider and configure its behavior, rather than needing to include those values in every resource and data source. It is usually used to gather credentials, endpoints, and the other data used to authenticate with the API, but it is not limited to those uses.
8299

website/docs/plugin/framework/resources/index.mdx

+3-3
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func (r *ThingResource) Metadata(ctx context.Context, req resource.MetadataReque
4949
}
5050
```
5151

52-
To simplify resource implementations, the [`provider.MetadataResponse.TypeName` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#MetadataResponse.TypeName) from the [`provider.ProviderWithMetadata` interface `Metadata` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#ProviderWithMetadata.Metadata) can set the provider name so it is available in the [`resource.MetadataRequest.ProviderTypeName` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#MetadataRequest.ProviderTypeName).
52+
To simplify resource implementations, the [`provider.MetadataResponse.TypeName` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#MetadataResponse.TypeName) from the [`provider.Provider` interface `Metadata` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#Provider.Metadata) can set the provider name so it is available in the [`resource.MetadataRequest.ProviderTypeName` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#MetadataRequest.ProviderTypeName).
5353

5454
In this example, the provider defines the `examplecloud` name for itself, and the data source is named `examplecloud_thing`:
5555

@@ -65,9 +65,9 @@ func (d *ThingDataSource) Metadata(ctx context.Context, req resource.MetadataReq
6565
}
6666
```
6767

68-
### GetSchema Method
68+
### Schema Method
6969

70-
The [`resource.Resource` interface `GetSchema` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#Resource.GetSchema) defines a [schema](/plugin/framework/schemas) describing what data is available in the resource's configuration, plan, and state.
70+
The [`resource.Resource` interface `Schema` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#Resource.Schema) defines a [schema](/plugin/framework/schemas) describing what data is available in the resource's configuration, plan, and state.
7171

7272
## Add Resource to Provider
7373

0 commit comments

Comments
 (0)