Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
provider: Deprecate
DataSourceType
, ResourceType
, Provider
type…
… `GetDataSources`, and `Provider` type `GetResources` (#472) Reference: #441 Reference: #442 The goal of this change is twofold: - Deprecate the separate `DataSourceType` and `ResourceType` types. - Enable `DataSource` and `Resource` to be self-documenting with respects to their type name. Removing `DataSourceType` and `ResourceType` simplifies provider implementations and gives developers the choice of whether or not to configure extra data in their `DataSource` and `Resource` implementations by adding the optional `Configure` method. This data is no longer required to be the `provider.Provider` itself, but rather can be any type such as a provider-defined structure or vendor-supplied client type. Enabling `DataSource` and `Resource` type name handling within the implementation allows provider developers to further split out their data source and resource code across package boundaries without repeated map addition logic. Given this framework version 0.11.1 code (which generally is split across Go files/packages, but shown altogether here for brevity): ```go var _ provider.Provider = &ExampleProvider{} type ExampleProvider struct{ configured bool // ... additional remote client fields, etc. } func (p ExampleProvider) GetDataSources(ctx context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { return map[string]provider.DataSourceType{ "example_thing": ThingDataSourceType{}, }, nil } func (p ExampleProvider) GetResources(ctx context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { return map[string]provider.ResourceType{ "example_thing": ThingResourceType{}, }, nil } func (p ExampleProvider) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { /* ... */ } func (p *ExampleProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { // ... remote client setup, etc. p.configured = true } var _ provider.DataSourceType = ThingDataSourceType{} var _ datasource.DataSource = ThingDataSource{} type ThingDataSourceType struct{} type ThingDataSource struct{ provider ExampleProvider } func (t ThingDataSourceType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { /* ... */ } func (t ThingDataSourceType) NewDataSource(ctx context.Context, p provider.Provider) (datasource.DataSource, diag.Diagnostics) { return ThingDataSource{ provider: p.(ExampleProvider), // unchecked type assertion shown for brevity } } func (d ThingDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // e.g. d.provider.Client.ReadThing() } var _ provider.ResourceType = ThingResourceType{} var _ resource.Resource = ThingResource{} type ThingResourceType struct{} type ThingResource struct{ provider ExampleProvider } func (t ThingResourceType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { /* ... */ } func (t ThingResourceType) NewResource(ctx context.Context, p provider.Provider) (resource.Resource, diag.Diagnostics) { return ThingResource{ provider: p.(ExampleProvider), // unchecked type assertion shown for brevity } } func (r ThingResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // e.g. r.provider.Client.CreateThing() } func (r ThingResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // e.g. r.provider.Client.DeleteThing() } func (r ThingResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // e.g. r.provider.Client.ReadThing() } func (r ThingResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { // e.g. r.provider.Client.UpdateThing() } ``` Could be migrated as: ```go type ExampleClient struct { // client/data fields OR just use the vendor client type directly instead of this new type } var _ provider.Provider = &ExampleProvider{} type ExampleProvider struct{ // setting client, etc. fields here is now completely optional, // if you want to configure data sources and resource with _this_ type } func (p ExampleProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) { // make available in DataSource and Resource type TypeName methods resp.TypeName = "example" } func (p ExampleProvider) DataSources(ctx context.Context) []func() datasource.DataSource { return []func() datasource.DataSource{ NewThingDataSource, } } func (p ExampleProvider) Resources(ctx context.Context) []func() resource.Resource { return []func() resource.Resource{ NewThingResource, } } func (p ExampleProvider) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { /* ... */ } func (p *ExampleProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { client := &ExampleClient{} // OR existing vendor type OR p itself resp.DataSourceData = client resp.ResourceData = client } var _ datasource.DataSource = &ThingDataSource{} func NewThingDataSource() datasource.DataSource { return &ThingDataSource{} } type ThingDataSource struct{ client *ExampleClient } func (d *ThingDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_thing" } func (d *ThingDataSource) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { /* ... */ } func (d *ThingDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { d.client = req.ProviderData.(*ExampleClient) // unchecked type assertion shown for brevity } func (d *ThingDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // e.g. d.client.ReadThing() } var _ resource.Resource = &ThingResource{} func NewThingResource() resource.Resource { return &ThingResource{} } type ThingResource struct{ client *ExampleClient } func (r *ThingResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_thing" } func (r *ThingResource) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { /* ... */ } func (r *ThingResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { r.client = req.ProviderData.(*ExampleClient) // unchecked type assertion shown for brevity } func (r *ThingResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // e.g. r.client.CreateThing() } func (r *ThingResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // e.g. r.client.DeleteThing() } func (r *ThingResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // e.g. r.client.ReadThing() } func (r *ThingResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { // e.g. r.client.UpdateThing() } ``` Some additional implementation notes: - The new `Provider` type `Metadata` method is called at the beginning of the `GetProviderSchema` RPC and populates the provider type name for data source and resource type name requests. - The framework server will automatically validate against duplicate type names, missing type names, and missing schemas when using the new `Provider` type `DataSources` and `Resources` methods. - The new `DataSource` and `Resource` type `Configure` methods are automatically called where the framework server previously called the `DataSourceType` type `NewDataSource` method and `ResourceType` type `NewResource` method.
- Loading branch information