Updates for framework provider.DataSourceType and provider.ResourceType deprecations (#86)

This commit is contained in:
Brian Flad 2022-09-12 15:59:37 -04:00 committed by GitHub
parent 30da51cc5d
commit 486074a22a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 167 additions and 160 deletions

View File

@ -23,4 +23,4 @@ provider "scaffolding" {
### Optional
- `example` (String) Example provider attribute
- `endpoint` (String) Example provider attribute

4
go.mod
View File

@ -4,7 +4,7 @@ go 1.18
require (
github.com/hashicorp/terraform-plugin-docs v0.13.0
github.com/hashicorp/terraform-plugin-framework v0.11.1
github.com/hashicorp/terraform-plugin-framework v0.12.0
github.com/hashicorp/terraform-plugin-go v0.14.0
github.com/hashicorp/terraform-plugin-log v0.7.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.22.0
@ -21,7 +21,7 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-checkpoint v0.5.0 // indirect

7
go.sum
View File

@ -94,8 +94,9 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
@ -138,8 +139,8 @@ github.com/hashicorp/terraform-json v0.14.0 h1:sh9iZ1Y8IFJLx+xQiKHGud6/TSUCM0N8e
github.com/hashicorp/terraform-json v0.14.0/go.mod h1:5A9HIWPkk4e5aeeXIBbkcOvaZbIYnAIkEyqP2pNSckM=
github.com/hashicorp/terraform-plugin-docs v0.13.0 h1:6e+VIWsVGb6jYJewfzq2ok2smPzZrt1Wlm9koLeKazY=
github.com/hashicorp/terraform-plugin-docs v0.13.0/go.mod h1:W0oCmHAjIlTHBbvtppWHe8fLfZ2BznQbuv8+UD8OucQ=
github.com/hashicorp/terraform-plugin-framework v0.11.1 h1:rq8f+TLDO4tJu+n9mMYlDrcRoIdrg0gTUvV2Jr0Ya24=
github.com/hashicorp/terraform-plugin-framework v0.11.1/go.mod h1:GENReHOz6GEt8Jk3UN94vk8BdC6irEHFgN3Z9HPhPUU=
github.com/hashicorp/terraform-plugin-framework v0.12.0 h1:Bk3l5MQUaZoo5eplr+u1FomYqGS564e8Tp3rutnCfYg=
github.com/hashicorp/terraform-plugin-framework v0.12.0/go.mod h1:wcZdk4+Uef6Ng+BiBJjGAcIPlIs5bhlEV/TA1k6Xkq8=
github.com/hashicorp/terraform-plugin-go v0.14.0 h1:ttnSlS8bz3ZPYbMb84DpcPhY4F5DsQtcAS7cHo8uvP4=
github.com/hashicorp/terraform-plugin-go v0.14.0/go.mod h1:2nNCBeRLaenyQEi78xrGrs9hMbulveqG/zDMQSvVJTE=
github.com/hashicorp/terraform-plugin-log v0.7.0 h1:SDxJUyT8TwN4l5b5/VkiTIaQgY6R+Y2BQ0sRZftGKQs=

View File

@ -2,22 +2,39 @@ package provider
import (
"context"
"fmt"
"net/http"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
)
// Ensure provider defined types fully satisfy framework interfaces
var _ provider.DataSourceType = exampleDataSourceType{}
var _ datasource.DataSource = exampleDataSource{}
var _ datasource.DataSource = &ExampleDataSource{}
type exampleDataSourceType struct{}
func NewExampleDataSource() datasource.DataSource {
return &ExampleDataSource{}
}
func (t exampleDataSourceType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
// ExampleDataSource defines the data source implementation.
type ExampleDataSource struct {
client *http.Client
}
// ExampleDataSourceModel describes the data source data model.
type ExampleDataSourceModel struct {
ConfigurableAttribute types.String `tfsdk:"configurable_attribute"`
Id types.String `tfsdk:"id"`
}
func (d *ExampleDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_example"
}
func (d *ExampleDataSource) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfsdk.Schema{
// This description is used by the documentation generator and the language server.
MarkdownDescription: "Example data source",
@ -37,28 +54,31 @@ func (t exampleDataSourceType) GetSchema(ctx context.Context) (tfsdk.Schema, dia
}, nil
}
func (t exampleDataSourceType) NewDataSource(ctx context.Context, in provider.Provider) (datasource.DataSource, diag.Diagnostics) {
provider, diags := convertProviderType(in)
return exampleDataSource{
provider: provider,
}, diags
func (d *ExampleDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}
type exampleDataSourceData struct {
ConfigurableAttribute types.String `tfsdk:"configurable_attribute"`
Id types.String `tfsdk:"id"`
client, ok := req.ProviderData.(*http.Client)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Data Source Configure Type",
fmt.Sprintf("Expected *http.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)
return
}
type exampleDataSource struct {
provider scaffoldingProvider
d.client = client
}
func (d exampleDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data exampleDataSourceData
func (d *ExampleDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data ExampleDataSourceModel
diags := req.Config.Get(ctx, &data)
resp.Diagnostics.Append(diags...)
// Read Terraform configuration data into the model
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
@ -66,7 +86,7 @@ func (d exampleDataSource) Read(ctx context.Context, req datasource.ReadRequest,
// If applicable, this is a great opportunity to initialize any necessary
// provider client data and make a call using it.
// example, err := d.provider.client.ReadExample(...)
// httpResp, err := d.client.Do(httpReq)
// if err != nil {
// resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read example, got error: %s", err))
// return
@ -80,6 +100,6 @@ func (d exampleDataSource) Read(ctx context.Context, req datasource.ReadRequest,
// Documentation: https://terraform.io/plugin/log
tflog.Trace(ctx, "read a data source")
diags = resp.State.Set(ctx, &data)
resp.Diagnostics.Append(diags...)
// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

View File

@ -2,10 +2,11 @@ package provider
import (
"context"
"fmt"
"net/http"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
@ -13,13 +14,29 @@ import (
)
// Ensure provider defined types fully satisfy framework interfaces
var _ provider.ResourceType = exampleResourceType{}
var _ resource.Resource = exampleResource{}
var _ resource.ResourceWithImportState = exampleResource{}
var _ resource.Resource = &ExampleResource{}
var _ resource.ResourceWithImportState = &ExampleResource{}
type exampleResourceType struct{}
func NewExampleResource() resource.Resource {
return &ExampleResource{}
}
func (t exampleResourceType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
// ExampleResource defines the resource implementation.
type ExampleResource struct {
client *http.Client
}
// ExampleResourceModel describes the resource data model.
type ExampleResourceModel struct {
ConfigurableAttribute types.String `tfsdk:"configurable_attribute"`
Id types.String `tfsdk:"id"`
}
func (r *ExampleResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_example"
}
func (r *ExampleResource) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfsdk.Schema{
// This description is used by the documentation generator and the language server.
MarkdownDescription: "Example resource",
@ -42,28 +59,31 @@ func (t exampleResourceType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.
}, nil
}
func (t exampleResourceType) NewResource(ctx context.Context, in provider.Provider) (resource.Resource, diag.Diagnostics) {
provider, diags := convertProviderType(in)
return exampleResource{
provider: provider,
}, diags
func (r *ExampleResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}
type exampleResourceData struct {
ConfigurableAttribute types.String `tfsdk:"configurable_attribute"`
Id types.String `tfsdk:"id"`
client, ok := req.ProviderData.(*http.Client)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Resource Configure Type",
fmt.Sprintf("Expected *http.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)
return
}
type exampleResource struct {
provider scaffoldingProvider
r.client = client
}
func (r exampleResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data exampleResourceData
func (r *ExampleResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data *ExampleResourceModel
diags := req.Config.Get(ctx, &data)
resp.Diagnostics.Append(diags...)
// Read Terraform plan data into the model
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
@ -71,7 +91,7 @@ func (r exampleResource) Create(ctx context.Context, req resource.CreateRequest,
// If applicable, this is a great opportunity to initialize any necessary
// provider client data and make a call using it.
// example, err := d.provider.client.CreateExample(...)
// httpResp, err := d.client.Do(httpReq)
// if err != nil {
// resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to create example, got error: %s", err))
// return
@ -85,15 +105,15 @@ func (r exampleResource) Create(ctx context.Context, req resource.CreateRequest,
// Documentation: https://terraform.io/plugin/log
tflog.Trace(ctx, "created a resource")
diags = resp.State.Set(ctx, &data)
resp.Diagnostics.Append(diags...)
// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
func (r exampleResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data exampleResourceData
func (r *ExampleResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data *ExampleResourceModel
diags := req.State.Get(ctx, &data)
resp.Diagnostics.Append(diags...)
// Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
@ -101,21 +121,21 @@ func (r exampleResource) Read(ctx context.Context, req resource.ReadRequest, res
// If applicable, this is a great opportunity to initialize any necessary
// provider client data and make a call using it.
// example, err := d.provider.client.ReadExample(...)
// httpResp, err := d.client.Do(httpReq)
// if err != nil {
// resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read example, got error: %s", err))
// return
// }
diags = resp.State.Set(ctx, &data)
resp.Diagnostics.Append(diags...)
// Save updated data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
func (r exampleResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data exampleResourceData
func (r *ExampleResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data *ExampleResourceModel
diags := req.Plan.Get(ctx, &data)
resp.Diagnostics.Append(diags...)
// Read Terraform plan data into the model
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
@ -123,21 +143,21 @@ func (r exampleResource) Update(ctx context.Context, req resource.UpdateRequest,
// If applicable, this is a great opportunity to initialize any necessary
// provider client data and make a call using it.
// example, err := d.provider.client.UpdateExample(...)
// httpResp, err := d.client.Do(httpReq)
// if err != nil {
// resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to update example, got error: %s", err))
// return
// }
diags = resp.State.Set(ctx, &data)
resp.Diagnostics.Append(diags...)
// Save updated data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
func (r exampleResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var data exampleResourceData
func (r *ExampleResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var data *ExampleResourceModel
diags := req.State.Get(ctx, &data)
resp.Diagnostics.Append(diags...)
// Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
@ -145,13 +165,13 @@ func (r exampleResource) Delete(ctx context.Context, req resource.DeleteRequest,
// If applicable, this is a great opportunity to initialize any necessary
// provider client data and make a call using it.
// example, err := d.provider.client.DeleteExample(...)
// httpResp, err := d.client.Do(httpReq)
// if err != nil {
// resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete example, got error: %s", err))
// return
// }
}
func (r exampleResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
func (r *ExampleResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}

View File

@ -2,77 +2,42 @@ package provider
import (
"context"
"fmt"
"net/http"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
)
// Ensure provider defined types fully satisfy framework interfaces
var _ provider.Provider = &scaffoldingProvider{}
// provider satisfies the tfsdk.Provider interface and usually is included
// with all Resource and DataSource implementations.
type scaffoldingProvider struct {
// client can contain the upstream provider SDK or HTTP client used to
// communicate with the upstream service. Resource and DataSource
// implementations can then make calls using this client.
//
// TODO: If appropriate, implement upstream provider SDK or HTTP client.
// client vendorsdk.ExampleClient
// configured is set to true at the end of the Configure method.
// This can be used in Resource and DataSource implementations to verify
// that the provider was previously configured.
configured bool
// Ensure ScaffoldingProvider satisfies various provider interfaces.
var _ provider.Provider = &ScaffoldingProvider{}
var _ provider.ProviderWithMetadata = &ScaffoldingProvider{}
// ScaffoldingProvider defines the provider implementation.
type ScaffoldingProvider struct {
// version is set to the provider version on release, "dev" when the
// provider is built and ran locally, and "test" when running acceptance
// testing.
version string
}
// providerData can be used to store data from the Terraform configuration.
type providerData struct {
Example types.String `tfsdk:"example"`
// ScaffoldingProviderModel describes the provider data model.
type ScaffoldingProviderModel struct {
Endpoint types.String `tfsdk:"endpoint"`
}
func (p *scaffoldingProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
var data providerData
diags := req.Config.Get(ctx, &data)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
func (p *ScaffoldingProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "scaffolding"
resp.Version = p.version
}
// Configuration values are now available.
// if data.Example.Null { /* ... */ }
// If the upstream provider SDK or HTTP client requires configuration, such
// as authentication or logging, this is a great opportunity to do so.
p.configured = true
}
func (p *scaffoldingProvider) GetResources(ctx context.Context) (map[string]provider.ResourceType, diag.Diagnostics) {
return map[string]provider.ResourceType{
"scaffolding_example": exampleResourceType{},
}, nil
}
func (p *scaffoldingProvider) GetDataSources(ctx context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) {
return map[string]provider.DataSourceType{
"scaffolding_example": exampleDataSourceType{},
}, nil
}
func (p *scaffoldingProvider) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
func (p *ScaffoldingProvider) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) {
return tfsdk.Schema{
Attributes: map[string]tfsdk.Attribute{
"example": {
"endpoint": {
MarkdownDescription: "Example provider attribute",
Optional: true,
Type: types.StringType,
@ -81,39 +46,40 @@ func (p *scaffoldingProvider) GetSchema(ctx context.Context) (tfsdk.Schema, diag
}, nil
}
func (p *ScaffoldingProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
var data ScaffoldingProviderModel
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
// Configuration values are now available.
// if data.Endpoint.IsNull() { /* ... */ }
// Example client configuration for data sources and resources
client := http.DefaultClient
resp.DataSourceData = client
resp.ResourceData = client
}
func (p *ScaffoldingProvider) Resources(ctx context.Context) []func() resource.Resource {
return []func() resource.Resource{
NewExampleResource,
}
}
func (p *ScaffoldingProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{
NewExampleDataSource,
}
}
func New(version string) func() provider.Provider {
return func() provider.Provider {
return &scaffoldingProvider{
return &ScaffoldingProvider{
version: version,
}
}
}
// convertProviderType is a helper function for NewResource and NewDataSource
// implementations to associate the concrete provider type. Alternatively,
// this helper can be skipped and the provider type can be directly type
// asserted (e.g. provider: in.(*scaffoldingProvider)), however using this can prevent
// potential panics.
func convertProviderType(in provider.Provider) (scaffoldingProvider, diag.Diagnostics) {
var diags diag.Diagnostics
p, ok := in.(*scaffoldingProvider)
if !ok {
diags.AddError(
"Unexpected Provider Instance Type",
fmt.Sprintf("While creating the data source or resource, an unexpected provider type (%T) was received. This is always a bug in the provider code and should be reported to the provider developers.", p),
)
return scaffoldingProvider{}, diags
}
if p == nil {
diags.AddError(
"Unexpected Provider Instance Type",
"While creating the data source or resource, an unexpected empty provider instance was received. This is always a bug in the provider code and should be reported to the provider developers.",
)
return scaffoldingProvider{}, diags
}
return *p, diags
}