Skip to content

Commit

Permalink
provider: Require Metadata method for Provider interface
Browse files Browse the repository at this point in the history
To remove potential confusion about optionally specifying this information. In the future, the provider metadata can be expanded further for documentation generation purposes.
  • Loading branch information
bflad committed Dec 13, 2022
1 parent ea5dd66 commit 8434065
Show file tree
Hide file tree
Showing 11 changed files with 114 additions and 110 deletions.
3 changes: 3 additions & 0 deletions .changelog/pending.txt
@@ -0,0 +1,3 @@
```release-note:breaking-change
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.
```
16 changes: 6 additions & 10 deletions internal/fwserver/server_getproviderschema.go
Expand Up @@ -30,18 +30,14 @@ func (s *Server) GetProviderSchema(ctx context.Context, req *GetProviderSchemaRe
PlanDestroy: true,
}

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

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

logging.FrameworkDebug(ctx, "Calling provider defined Provider Metadata")
providerWithMetadata.Metadata(ctx, metadataReq, &metadataResp)
logging.FrameworkDebug(ctx, "Called provider defined Provider Metadata")

s.providerTypeName = metadataResp.TypeName
}
s.providerTypeName = metadataResp.TypeName

providerSchema, diags := s.ProviderSchema(ctx)

Expand Down
80 changes: 38 additions & 42 deletions internal/fwserver/server_getproviderschema_test.go
Expand Up @@ -258,31 +258,29 @@ func TestServerGetProviderSchema(t *testing.T) {
},
"datasourceschemas-provider-type-name": {
server: &fwserver.Server{
Provider: &testprovider.ProviderWithMetadata{
Provider: &testprovider.Provider{
MetadataMethod: func(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "testprovidertype"
},
Provider: &testprovider.Provider{
DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{
func() datasource.DataSource {
return &testprovider.DataSource{
SchemaMethod: func(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = datasourceschema.Schema{
Attributes: map[string]datasourceschema.Attribute{
"test": datasourceschema.StringAttribute{
Required: true,
},
DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{
func() datasource.DataSource {
return &testprovider.DataSource{
SchemaMethod: func(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = datasourceschema.Schema{
Attributes: map[string]datasourceschema.Attribute{
"test": datasourceschema.StringAttribute{
Required: true,
},
}
},
MetadataMethod: func(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_data_source"
},
}
},
}
},
},
}
},
MetadataMethod: func(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_data_source"
},
}
},
}
},
},
},
Expand Down Expand Up @@ -640,31 +638,29 @@ func TestServerGetProviderSchema(t *testing.T) {
},
"resourceschemas-provider-type-name": {
server: &fwserver.Server{
Provider: &testprovider.ProviderWithMetadata{
Provider: &testprovider.Provider{
MetadataMethod: func(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "testprovidertype"
},
Provider: &testprovider.Provider{
ResourcesMethod: func(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
func() resource.Resource {
return &testprovider.Resource{
SchemaMethod: func(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = resourceschema.Schema{
Attributes: map[string]resourceschema.Attribute{
"test": resourceschema.StringAttribute{
Required: true,
},
ResourcesMethod: func(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
func() resource.Resource {
return &testprovider.Resource{
SchemaMethod: func(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = resourceschema.Schema{
Attributes: map[string]resourceschema.Attribute{
"test": resourceschema.StringAttribute{
Required: true,
},
}
},
MetadataMethod: func(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_resource"
},
}
},
}
},
},
}
},
MetadataMethod: func(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_resource"
},
}
},
}
},
},
},
Expand Down
10 changes: 10 additions & 0 deletions internal/proto5server/server_getproviderschema_test.go
Expand Up @@ -514,6 +514,16 @@ func TestServerGetProviderSchema_logging(t *testing.T) {
}

expectedEntries := []map[string]interface{}{
{
"@level": "debug",
"@message": "Calling provider defined Provider Metadata",
"@module": "sdk.framework",
},
{
"@level": "debug",
"@message": "Called provider defined Provider Metadata",
"@module": "sdk.framework",
},
{
"@level": "trace",
"@message": "Checking ProviderSchema lock",
Expand Down
10 changes: 10 additions & 0 deletions internal/proto6server/server_getproviderschema_test.go
Expand Up @@ -514,6 +514,16 @@ func TestServerGetProviderSchema_logging(t *testing.T) {
}

expectedEntries := []map[string]interface{}{
{
"@level": "debug",
"@message": "Calling provider defined Provider Metadata",
"@module": "sdk.framework",
},
{
"@level": "debug",
"@message": "Called provider defined Provider Metadata",
"@module": "sdk.framework",
},
{
"@level": "trace",
"@message": "Checking ProviderSchema lock",
Expand Down
26 changes: 16 additions & 10 deletions internal/testing/testprovider/provider.go
Expand Up @@ -13,17 +13,14 @@ var _ provider.Provider = &Provider{}
// Declarative provider.Provider for unit testing.
type Provider struct {
// Provider interface methods
ConfigureMethod func(context.Context, provider.ConfigureRequest, *provider.ConfigureResponse)
SchemaMethod func(context.Context, provider.SchemaRequest, *provider.SchemaResponse)

// ProviderWithDataSources interface methods
MetadataMethod func(context.Context, provider.MetadataRequest, *provider.MetadataResponse)
ConfigureMethod func(context.Context, provider.ConfigureRequest, *provider.ConfigureResponse)
SchemaMethod func(context.Context, provider.SchemaRequest, *provider.SchemaResponse)
DataSourcesMethod func(context.Context) []func() datasource.DataSource

// ProviderWithResources interface methods
ResourcesMethod func(context.Context) []func() resource.Resource
ResourcesMethod func(context.Context) []func() resource.Resource
}

// GetSchema satisfies the provider.Provider interface.
// Configure satisfies the provider.Provider interface.
func (p *Provider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
if p == nil || p.ConfigureMethod == nil {
return
Expand All @@ -32,7 +29,7 @@ func (p *Provider) Configure(ctx context.Context, req provider.ConfigureRequest,
p.ConfigureMethod(ctx, req, resp)
}

// DataSources satisfies the provider.ProviderWithDataSources interface.
// DataSources satisfies the provider.Provider interface.
func (p *Provider) DataSources(ctx context.Context) []func() datasource.DataSource {
if p == nil || p.DataSourcesMethod == nil {
return nil
Expand All @@ -41,6 +38,15 @@ func (p *Provider) DataSources(ctx context.Context) []func() datasource.DataSour
return p.DataSourcesMethod(ctx)
}

// Metadata satisfies the provider.Provider interface.
func (p *Provider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
if p == nil || p.MetadataMethod == nil {
return
}

p.MetadataMethod(ctx, req, resp)
}

// Schema satisfies the provider.Provider interface.
func (p *Provider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
if p == nil || p.SchemaMethod == nil {
Expand All @@ -50,7 +56,7 @@ func (p *Provider) Schema(ctx context.Context, req provider.SchemaRequest, resp
p.SchemaMethod(ctx, req, resp)
}

// Resources satisfies the provider.ProviderWithResources interface.
// Resources satisfies the provider.Provider interface.
func (p *Provider) Resources(ctx context.Context) []func() resource.Resource {
if p == nil || p.ResourcesMethod == nil {
return nil
Expand Down
27 changes: 0 additions & 27 deletions internal/testing/testprovider/providerwithmetadata.go

This file was deleted.

23 changes: 8 additions & 15 deletions provider/provider.go
Expand Up @@ -15,6 +15,14 @@ import (
// via ProviderWithConfigValidators or ProviderWithValidateConfig.
// - Meta Schema: ProviderWithMetaSchema
type Provider interface {
// Metadata should return the metadata for the provider, such as
// a type name and version data.
//
// Implementing the MetadataResponse.TypeName will populate the
// datasource.MetadataRequest.ProviderTypeName and
// resource.MetadataRequest.ProviderTypeName fields automatically.
Metadata(context.Context, MetadataRequest, *MetadataResponse)

// Schema should return the schema for this provider.
Schema(context.Context, SchemaRequest, *SchemaResponse)

Expand Down Expand Up @@ -57,21 +65,6 @@ type ProviderWithConfigValidators interface {
ConfigValidators(context.Context) []ConfigValidator
}

// ProviderWithMetadata is an interface type that extends Provider to
// return its type name, such as examplecloud, and other
// metadata, such as version.
//
// Implementing this method will populate the
// [datasource.MetadataRequest.ProviderTypeName] and
// [resource.MetadataRequest.ProviderTypeName] fields automatically.
type ProviderWithMetadata interface {
Provider

// Metadata should return the metadata for the provider, such as
// a type name and version data.
Metadata(context.Context, MetadataRequest, *MetadataResponse)
}

// ProviderWithMetaSchema is a provider with a provider meta schema, which
// is configured by practitioners via the provider_meta configuration block
// and the configuration data is included with certain data source and resource
Expand Down
2 changes: 1 addition & 1 deletion website/docs/plugin/framework/data-sources/index.mdx
Expand Up @@ -79,7 +79,7 @@ func (d *ThingDataSource) Metadata(ctx context.Context, req datasource.MetadataR
}
```

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).
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).

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

Expand Down
21 changes: 19 additions & 2 deletions website/docs/plugin/framework/providers/index.mdx
Expand Up @@ -35,7 +35,12 @@ type ExampleCloudProvider struct{
Version string
}

// GetSchema satisfies the provider.Provider interface for exampleProvider.
// Metadata satisfies the provider.Provider interface for ExampleCloudProvider
func (p *ExampleCloudProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = // provider specific implementation
}

// Schema satisfies the provider.Provider interface for ExampleCloudProvider.
func (p *ExampleCloudProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
Expand Down Expand Up @@ -76,7 +81,19 @@ func New(version string) func() provider.Provider {
}
```

### GetSchema Method
### Metadata Method

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.

In this example, the provider type name is set to `examplecloud`:

```go
func (p *ExampleCloudProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "examplecloud"
}
```

### Schema Method

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.

Expand Down
6 changes: 3 additions & 3 deletions website/docs/plugin/framework/resources/index.mdx
Expand Up @@ -49,7 +49,7 @@ func (r *ThingResource) Metadata(ctx context.Context, req resource.MetadataReque
}
```

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).
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).

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

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

### GetSchema Method
### Schema Method

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.
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.

## Add Resource to Provider

Expand Down

0 comments on commit 8434065

Please sign in to comment.