diff --git a/.changelog/472.txt b/.changelog/472.txt new file mode 100644 index 000000000..7a81faa4a --- /dev/null +++ b/.changelog/472.txt @@ -0,0 +1,43 @@ +```release-note:enhancement +datasource: The `DataSource` type `GetSchema` and `Metadata` methods will be required in the next version. +``` + +```release-note:note +provider: The `DataSourceType` type has been deprecated in preference of moving the `GetSchema` method to the `datasource.DataSource` type and optionally implementing the `NewResource` method logic to a new `Configure` method. The `DataSourceType` type will be removed in the next version. +``` + +```release-note:note +provider: The `Provider` type `GetDataSources` method has been deprecated in preference of the `DataSources` method. All `datasource.DataSource` types must implement the `Metadata` method after migrating. Support for the `GetDataSources` method will be removed in the next version. +``` + +```release-note:note +provider: The `Provider` type `GetResources` method has been deprecated in preference of the `Resources` method. All `resource.Resource` types must implement the `Metadata` method after migrating. Support for the `GetResources` method will be removed in the next version. +``` + +```release-note:note +provider: The `ResourceType` type has been deprecated in preference of moving the `GetSchema` method to the `resource.Resource` type and optionally implementing the `NewResource` method logic to a new `Configure` method. The `ResourceType` type will be removed in the next version. +``` + +```release-note:note +resource: The `Resource` type `GetSchema` and `Metadata` methods will be required in the next version. +``` + +```release-note:enhancement +datasource: Added `DataSource` type `Configure`, `GetSchema`, and `Metadata` method support +``` + +```release-note:enhancement +provider: Added `ConfigureResponse` type `DataSourceData` field, which will set the `datasource.ConfigureRequest.ProviderData` field +``` + +```release-note:enhancement +provider: Added `ConfigureResponse` type `ResourceData` field, which will set the `resource.ConfigureRequest.ProviderData` field +``` + +```release-note:enhancement +provider: Added `Provider` type `Metadata` method support, which the `MetadataResponse.TypeName` field will set the `datasource.MetadataRequest.ProviderTypeName` and `resource.MetadataRequest.ProviderTypeName` fields +``` + +```release-note:enhancement +resource: Added `Resource` type `Configure`, `GetSchema`, and `Metadata` method support +``` diff --git a/datasource/configure.go b/datasource/configure.go new file mode 100644 index 000000000..d2212e966 --- /dev/null +++ b/datasource/configure.go @@ -0,0 +1,31 @@ +package datasource + +import ( + "github.com/hashicorp/terraform-plugin-framework/diag" +) + +// ConfigureRequest represents a request for the provider to configure a data +// source, i.e., set provider-level data or clients. An instance of this +// request struct is supplied as an argument to the DataSource type Configure +// method. +type ConfigureRequest struct { + // ProviderData is the data set in the + // [provider.ConfigureResponse.DataSourceData] field. This data is + // provider-specifc and therefore can contain any necessary remote system + // clients, custom provider data, or anything else pertinent to the + // functionality of the DataSource. + // + // This data is only set after the ConfigureProvider RPC has been called + // by Terraform. + ProviderData any +} + +// ConfigureResponse represents a response to a ConfigureRequest. An +// instance of this response struct is supplied as an argument to the +// DataSource type Configure method. +type ConfigureResponse struct { + // Diagnostics report errors or warnings related to configuring of the + // Datasource. An empty slice indicates a successful operation with no + // warnings or errors generated. + Diagnostics diag.Diagnostics +} diff --git a/datasource/data_source.go b/datasource/data_source.go index 46e7d6ad9..0d74ab11e 100644 --- a/datasource/data_source.go +++ b/datasource/data_source.go @@ -1,12 +1,18 @@ package datasource -import "context" +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" +) // DataSource represents an instance of a data source type. This is the core // interface that all data sources must implement. // // Data sources can optionally implement these additional concepts: // +// - Configure: Include provider-level data or clients. // - Validation: Schema-based via tfsdk.Attribute or entire configuration // via DataSourceWithConfigValidators or DataSourceWithValidateConfig. type DataSource interface { @@ -16,6 +22,22 @@ type DataSource interface { Read(context.Context, ReadRequest, *ReadResponse) } +// DataSourceWithConfigure is an interface type that extends DataSource to +// include a method which the framework will automatically call so provider +// developers have the opportunity to setup any necessary provider-level data +// or clients in the DataSource type. +// +// This method is intended to replace the provider.DataSourceType type +// NewDataSource method in a future release. +type DataSourceWithConfigure interface { + DataSource + + // Configure enables provider-level data or clients to be set in the + // provider-defined DataSource type. It is separately executed for each + // ReadDataSource RPC. + Configure(context.Context, ConfigureRequest, *ConfigureResponse) +} + // DataSourceWithConfigValidators is an interface type that extends DataSource to include declarative validations. // // Declaring validation using this methodology simplifies implmentation of @@ -31,6 +53,30 @@ type DataSourceWithConfigValidators interface { ConfigValidators(context.Context) []ConfigValidator } +// DataSourceWithGetSchema is an interface type that extends DataSource to +// return its schema definition. +// +// This method will be required in the DataSource interface in a future +// release. +type DataSourceWithGetSchema interface { + // GetSchema returns the schema for this data source. + GetSchema(context.Context) (tfsdk.Schema, diag.Diagnostics) +} + +// DataSourceWithMetadata is an interface type that extends DataSource to +// return metadata, such as its data source type name. For example, if the +// provider is named examplecloud and the data source reads a thing, this +// should return examplecloud_thing. +// +// This method will be required in the DataSource interface a future release. +type DataSourceWithMetadata interface { + DataSource + + // Metadata should return the full name of the data source, such as + // examplecloud_thing. + Metadata(context.Context, MetadataRequest, *MetadataResponse) +} + // DataSourceWithValidateConfig is an interface type that extends DataSource to include imperative validation. // // Declaring validation using this methodology simplifies one-off diff --git a/datasource/doc.go b/datasource/doc.go index fd7a4fc82..9c9291791 100644 --- a/datasource/doc.go +++ b/datasource/doc.go @@ -5,14 +5,12 @@ // to offer practitioners a read-only source of information, which is saved // into the Terraform state and can be referenced by other parts of a // configuration. Data sources are defined by a data source type/name, such as -// "example_thing", a schema representing the structure and data types of +// "examplecloud_thing", a schema representing the structure and data types of // configuration and state, and read logic. // // The main starting point for implementations in this package is the // DataSource type which represents an instance of a data source type that has -// its own configuration, read logic, and state. A DataSource is instantiated -// from a provider.DataSourceType type NewDataSource method, which also defines -// the data source schema. The provider.DataSourceType types are referenced by -// a provider.Provider type GetDataSources method, which enables the data -// source for practitioner and testing usage. +// its own configuration, read logic, and state. The DataSource implementations +// are referenced by a [provider.Provider] type DataSources method, which +// enables the data source for practitioner and testing usage. package datasource diff --git a/datasource/metadata.go b/datasource/metadata.go new file mode 100644 index 000000000..37aef828d --- /dev/null +++ b/datasource/metadata.go @@ -0,0 +1,21 @@ +package datasource + +// MetadataRequest represents a request for the DataSource to return metadata, +// such as its type name. An instance of this request struct is supplied as an +// argument to the DataSource type Metadata method. +type MetadataRequest struct { + // ProviderTypeName is the string returned from + // [provider.MetadataResponse.TypeName], if the Provider type implements + // the Metadata method. This string should prefix the DataSource type name + // with an underscore in the response. + ProviderTypeName string +} + +// MetadataResponse represents a response to a MetadataRequest. An +// instance of this response struct is supplied as an argument to the +// DataSource type Metadata method. +type MetadataResponse struct { + // TypeName should be the full data source type, including the provider + // type prefix and an underscore. For example, examplecloud_thing. + TypeName string +} diff --git a/internal/fromproto5/applyresourcechange.go b/internal/fromproto5/applyresourcechange.go index c658bc4f7..c1f8d5b9a 100644 --- a/internal/fromproto5/applyresourcechange.go +++ b/internal/fromproto5/applyresourcechange.go @@ -9,12 +9,12 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" - "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/resource" ) // ApplyResourceChangeRequest returns the *fwserver.ApplyResourceChangeRequest // equivalent of a *tfprotov5.ApplyResourceChangeRequest. -func ApplyResourceChangeRequest(ctx context.Context, proto5 *tfprotov5.ApplyResourceChangeRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.ApplyResourceChangeRequest, diag.Diagnostics) { +func ApplyResourceChangeRequest(ctx context.Context, proto5 *tfprotov5.ApplyResourceChangeRequest, resource resource.Resource, resourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.ApplyResourceChangeRequest, diag.Diagnostics) { if proto5 == nil { return nil, nil } @@ -37,7 +37,7 @@ func ApplyResourceChangeRequest(ctx context.Context, proto5 *tfprotov5.ApplyReso fw := &fwserver.ApplyResourceChangeRequest{ ResourceSchema: resourceSchema, - ResourceType: resourceType, + Resource: resource, } config, configDiags := Config(ctx, proto5.Config, resourceSchema) diff --git a/internal/fromproto5/applyresourcechange_test.go b/internal/fromproto5/applyresourcechange_test.go index ce66d840d..8ffb384e7 100644 --- a/internal/fromproto5/applyresourcechange_test.go +++ b/internal/fromproto5/applyresourcechange_test.go @@ -13,7 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" - "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" ) @@ -57,7 +57,7 @@ func TestApplyResourceChangeRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov5.ApplyResourceChangeRequest resourceSchema fwschema.Schema - resourceType provider.ResourceType + resource resource.Resource providerMetaSchema fwschema.Schema expected *fwserver.ApplyResourceChangeRequest expectedDiagnostics diag.Diagnostics @@ -253,7 +253,7 @@ func TestApplyResourceChangeRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := fromproto5.ApplyResourceChangeRequest(context.Background(), testCase.input, testCase.resourceType, testCase.resourceSchema, testCase.providerMetaSchema) + got, diags := fromproto5.ApplyResourceChangeRequest(context.Background(), testCase.input, testCase.resource, testCase.resourceSchema, testCase.providerMetaSchema) if diff := cmp.Diff(got, testCase.expected, cmp.AllowUnexported(privatestate.ProviderData{})); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/internal/fromproto5/importresourcestate.go b/internal/fromproto5/importresourcestate.go index adaf9da8c..3ef08cbf3 100644 --- a/internal/fromproto5/importresourcestate.go +++ b/internal/fromproto5/importresourcestate.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "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-go/tfprotov5" "github.com/hashicorp/terraform-plugin-go/tftypes" @@ -14,7 +14,7 @@ import ( // ImportResourceStateRequest returns the *fwserver.ImportResourceStateRequest // equivalent of a *tfprotov5.ImportResourceStateRequest. -func ImportResourceStateRequest(ctx context.Context, proto5 *tfprotov5.ImportResourceStateRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema) (*fwserver.ImportResourceStateRequest, diag.Diagnostics) { +func ImportResourceStateRequest(ctx context.Context, proto5 *tfprotov5.ImportResourceStateRequest, resource resource.Resource, resourceSchema fwschema.Schema) (*fwserver.ImportResourceStateRequest, diag.Diagnostics) { if proto5 == nil { return nil, nil } @@ -40,9 +40,9 @@ func ImportResourceStateRequest(ctx context.Context, proto5 *tfprotov5.ImportRes Raw: tftypes.NewValue(resourceSchema.Type().TerraformType(ctx), nil), Schema: tfsdkSchema(resourceSchema), }, - ID: proto5.ID, - ResourceType: resourceType, - TypeName: proto5.TypeName, + ID: proto5.ID, + Resource: resource, + TypeName: proto5.TypeName, } return fw, diags diff --git a/internal/fromproto5/importresourcestate_test.go b/internal/fromproto5/importresourcestate_test.go index 788a52aa7..8dafd605a 100644 --- a/internal/fromproto5/importresourcestate_test.go +++ b/internal/fromproto5/importresourcestate_test.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fromproto5" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "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" "github.com/hashicorp/terraform-plugin-go/tfprotov5" @@ -36,7 +36,7 @@ func TestImportResourceStateRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov5.ImportResourceStateRequest resourceSchema fwschema.Schema - resourceType provider.ResourceType + resource resource.Resource expected *fwserver.ImportResourceStateRequest expectedDiagnostics diag.Diagnostics }{ @@ -92,7 +92,7 @@ func TestImportResourceStateRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := fromproto5.ImportResourceStateRequest(context.Background(), testCase.input, testCase.resourceType, testCase.resourceSchema) + got, diags := fromproto5.ImportResourceStateRequest(context.Background(), testCase.input, testCase.resource, testCase.resourceSchema) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/internal/fromproto5/planresourcechange.go b/internal/fromproto5/planresourcechange.go index 84239f79c..487337f07 100644 --- a/internal/fromproto5/planresourcechange.go +++ b/internal/fromproto5/planresourcechange.go @@ -9,12 +9,12 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" - "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/resource" ) // PlanResourceChangeRequest returns the *fwserver.PlanResourceChangeRequest // equivalent of a *tfprotov5.PlanResourceChangeRequest. -func PlanResourceChangeRequest(ctx context.Context, proto5 *tfprotov5.PlanResourceChangeRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.PlanResourceChangeRequest, diag.Diagnostics) { +func PlanResourceChangeRequest(ctx context.Context, proto5 *tfprotov5.PlanResourceChangeRequest, resource resource.Resource, resourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.PlanResourceChangeRequest, diag.Diagnostics) { if proto5 == nil { return nil, nil } @@ -37,7 +37,7 @@ func PlanResourceChangeRequest(ctx context.Context, proto5 *tfprotov5.PlanResour fw := &fwserver.PlanResourceChangeRequest{ ResourceSchema: resourceSchema, - ResourceType: resourceType, + Resource: resource, } config, configDiags := Config(ctx, proto5.Config, resourceSchema) diff --git a/internal/fromproto5/planresourcechange_test.go b/internal/fromproto5/planresourcechange_test.go index d25c47ab7..02d7edafa 100644 --- a/internal/fromproto5/planresourcechange_test.go +++ b/internal/fromproto5/planresourcechange_test.go @@ -13,7 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" - "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" ) @@ -55,7 +55,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov5.PlanResourceChangeRequest resourceSchema fwschema.Schema - resourceType provider.ResourceType + resource resource.Resource providerMetaSchema fwschema.Schema expected *fwserver.PlanResourceChangeRequest expectedDiagnostics diag.Diagnostics @@ -223,7 +223,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := fromproto5.PlanResourceChangeRequest(context.Background(), testCase.input, testCase.resourceType, testCase.resourceSchema, testCase.providerMetaSchema) + got, diags := fromproto5.PlanResourceChangeRequest(context.Background(), testCase.input, testCase.resource, testCase.resourceSchema, testCase.providerMetaSchema) if diff := cmp.Diff(got, testCase.expected, cmp.AllowUnexported(privatestate.ProviderData{})); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/internal/fromproto5/readdatasource.go b/internal/fromproto5/readdatasource.go index b390f4233..b183a1c15 100644 --- a/internal/fromproto5/readdatasource.go +++ b/internal/fromproto5/readdatasource.go @@ -3,16 +3,16 @@ package fromproto5 import ( "context" + "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-go/tfprotov5" ) // ReadDataSourceRequest returns the *fwserver.ReadDataSourceRequest // equivalent of a *tfprotov5.ReadDataSourceRequest. -func ReadDataSourceRequest(ctx context.Context, proto5 *tfprotov5.ReadDataSourceRequest, dataSourceType provider.DataSourceType, dataSourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.ReadDataSourceRequest, diag.Diagnostics) { +func ReadDataSourceRequest(ctx context.Context, proto5 *tfprotov5.ReadDataSourceRequest, dataSource datasource.DataSource, dataSourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.ReadDataSourceRequest, diag.Diagnostics) { if proto5 == nil { return nil, nil } @@ -34,8 +34,8 @@ func ReadDataSourceRequest(ctx context.Context, proto5 *tfprotov5.ReadDataSource } fw := &fwserver.ReadDataSourceRequest{ + DataSource: dataSource, DataSourceSchema: dataSourceSchema, - DataSourceType: dataSourceType, } config, configDiags := Config(ctx, proto5.Config, dataSourceSchema) diff --git a/internal/fromproto5/readdatasource_test.go b/internal/fromproto5/readdatasource_test.go index 949442790..943b8ba36 100644 --- a/internal/fromproto5/readdatasource_test.go +++ b/internal/fromproto5/readdatasource_test.go @@ -5,11 +5,11 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fromproto5" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "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-go/tfprotov5" @@ -47,7 +47,7 @@ func TestReadDataSourceRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov5.ReadDataSourceRequest dataSourceSchema fwschema.Schema - dataSourceType provider.DataSourceType + dataSource datasource.DataSource providerMetaSchema fwschema.Schema expected *fwserver.ReadDataSourceRequest expectedDiagnostics diag.Diagnostics @@ -141,7 +141,7 @@ func TestReadDataSourceRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := fromproto5.ReadDataSourceRequest(context.Background(), testCase.input, testCase.dataSourceType, testCase.dataSourceSchema, testCase.providerMetaSchema) + got, diags := fromproto5.ReadDataSourceRequest(context.Background(), testCase.input, testCase.dataSource, testCase.dataSourceSchema, testCase.providerMetaSchema) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/internal/fromproto5/readresource.go b/internal/fromproto5/readresource.go index ad20208ec..e4ddd83d5 100644 --- a/internal/fromproto5/readresource.go +++ b/internal/fromproto5/readresource.go @@ -9,12 +9,12 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" - "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/resource" ) // ReadResourceRequest returns the *fwserver.ReadResourceRequest // equivalent of a *tfprotov5.ReadResourceRequest. -func ReadResourceRequest(ctx context.Context, proto5 *tfprotov5.ReadResourceRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.ReadResourceRequest, diag.Diagnostics) { +func ReadResourceRequest(ctx context.Context, proto5 *tfprotov5.ReadResourceRequest, resource resource.Resource, resourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.ReadResourceRequest, diag.Diagnostics) { if proto5 == nil { return nil, nil } @@ -22,7 +22,7 @@ func ReadResourceRequest(ctx context.Context, proto5 *tfprotov5.ReadResourceRequ var diags diag.Diagnostics fw := &fwserver.ReadResourceRequest{ - ResourceType: resourceType, + Resource: resource, } currentState, currentStateDiags := State(ctx, proto5.CurrentState, resourceSchema) diff --git a/internal/fromproto5/readresource_test.go b/internal/fromproto5/readresource_test.go index b5f262944..c6bfdea64 100644 --- a/internal/fromproto5/readresource_test.go +++ b/internal/fromproto5/readresource_test.go @@ -13,7 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" - "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" ) @@ -57,7 +57,7 @@ func TestReadResourceRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov5.ReadResourceRequest resourceSchema fwschema.Schema - resourceType provider.ResourceType + resource resource.Resource providerMetaSchema fwschema.Schema expected *fwserver.ReadResourceRequest expectedDiagnostics diag.Diagnostics @@ -178,7 +178,7 @@ func TestReadResourceRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := fromproto5.ReadResourceRequest(context.Background(), testCase.input, testCase.resourceType, testCase.resourceSchema, testCase.providerMetaSchema) + got, diags := fromproto5.ReadResourceRequest(context.Background(), testCase.input, testCase.resource, testCase.resourceSchema, testCase.providerMetaSchema) if diff := cmp.Diff(got, testCase.expected, cmp.AllowUnexported(privatestate.ProviderData{})); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/internal/fromproto5/schema.go b/internal/fromproto5/schema.go index 267663916..dc75e8de7 100644 --- a/internal/fromproto5/schema.go +++ b/internal/fromproto5/schema.go @@ -14,6 +14,8 @@ import ( // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/366 func tfsdkSchema(s fwschema.Schema) tfsdk.Schema { switch s := s.(type) { + case tfsdk.Schema: + return s case *tfsdk.Schema: return *s default: diff --git a/internal/fromproto5/upgraderesourcestate.go b/internal/fromproto5/upgraderesourcestate.go index c8707134f..081b28cee 100644 --- a/internal/fromproto5/upgraderesourcestate.go +++ b/internal/fromproto5/upgraderesourcestate.go @@ -6,14 +6,14 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-go/tfprotov5" "github.com/hashicorp/terraform-plugin-go/tfprotov6" ) // UpgradeResourceStateRequest returns the *fwserver.UpgradeResourceStateRequest // equivalent of a *tfprotov5.UpgradeResourceStateRequest. -func UpgradeResourceStateRequest(ctx context.Context, proto5 *tfprotov5.UpgradeResourceStateRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema) (*fwserver.UpgradeResourceStateRequest, diag.Diagnostics) { +func UpgradeResourceStateRequest(ctx context.Context, proto5 *tfprotov5.UpgradeResourceStateRequest, resource resource.Resource, resourceSchema fwschema.Schema) (*fwserver.UpgradeResourceStateRequest, diag.Diagnostics) { if proto5 == nil { return nil, nil } @@ -37,7 +37,7 @@ func UpgradeResourceStateRequest(ctx context.Context, proto5 *tfprotov5.UpgradeR fw := &fwserver.UpgradeResourceStateRequest{ RawState: (*tfprotov6.RawState)(proto5.RawState), ResourceSchema: resourceSchema, - ResourceType: resourceType, + Resource: resource, Version: proto5.Version, } diff --git a/internal/fromproto5/upgraderesourcestate_test.go b/internal/fromproto5/upgraderesourcestate_test.go index c368c9fc3..342717feb 100644 --- a/internal/fromproto5/upgraderesourcestate_test.go +++ b/internal/fromproto5/upgraderesourcestate_test.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fromproto5" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "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" "github.com/hashicorp/terraform-plugin-go/tfprotov5" @@ -30,7 +30,7 @@ func TestUpgradeResourceStateRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov5.UpgradeResourceStateRequest resourceSchema fwschema.Schema - resourceType provider.ResourceType + resource resource.Resource expected *fwserver.UpgradeResourceStateRequest expectedDiagnostics diag.Diagnostics }{ @@ -90,7 +90,7 @@ func TestUpgradeResourceStateRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := fromproto5.UpgradeResourceStateRequest(context.Background(), testCase.input, testCase.resourceType, testCase.resourceSchema) + got, diags := fromproto5.UpgradeResourceStateRequest(context.Background(), testCase.input, testCase.resource, testCase.resourceSchema) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/internal/fromproto5/validatedatasourceconfig.go b/internal/fromproto5/validatedatasourceconfig.go index 5dc05f5d1..ce87987cc 100644 --- a/internal/fromproto5/validatedatasourceconfig.go +++ b/internal/fromproto5/validatedatasourceconfig.go @@ -3,16 +3,16 @@ package fromproto5 import ( "context" + "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-go/tfprotov5" ) // ValidateDataSourceConfigRequest returns the *fwserver.ValidateDataSourceConfigRequest // equivalent of a *tfprotov5.ValidateDataSourceConfigRequest. -func ValidateDataSourceConfigRequest(ctx context.Context, proto5 *tfprotov5.ValidateDataSourceConfigRequest, dataSourceType provider.DataSourceType, dataSourceSchema fwschema.Schema) (*fwserver.ValidateDataSourceConfigRequest, diag.Diagnostics) { +func ValidateDataSourceConfigRequest(ctx context.Context, proto5 *tfprotov5.ValidateDataSourceConfigRequest, dataSource datasource.DataSource, dataSourceSchema fwschema.Schema) (*fwserver.ValidateDataSourceConfigRequest, diag.Diagnostics) { if proto5 == nil { return nil, nil } @@ -22,7 +22,7 @@ func ValidateDataSourceConfigRequest(ctx context.Context, proto5 *tfprotov5.Vali config, diags := Config(ctx, proto5.Config, dataSourceSchema) fw.Config = config - fw.DataSourceType = dataSourceType + fw.DataSource = dataSource return fw, diags } diff --git a/internal/fromproto5/validatedatasourceconfig_test.go b/internal/fromproto5/validatedatasourceconfig_test.go index 4fde3951e..9591b0b0f 100644 --- a/internal/fromproto5/validatedatasourceconfig_test.go +++ b/internal/fromproto5/validatedatasourceconfig_test.go @@ -5,11 +5,11 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fromproto5" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "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-go/tfprotov5" @@ -47,7 +47,7 @@ func TestValidateDataSourceConfigRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov5.ValidateDataSourceConfigRequest dataSourceSchema fwschema.Schema - dataSourceType provider.DataSourceType + dataSource datasource.DataSource expected *fwserver.ValidateDataSourceConfigRequest expectedDiagnostics diag.Diagnostics }{ @@ -94,7 +94,7 @@ func TestValidateDataSourceConfigRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := fromproto5.ValidateDataSourceConfigRequest(context.Background(), testCase.input, testCase.dataSourceType, testCase.dataSourceSchema) + got, diags := fromproto5.ValidateDataSourceConfigRequest(context.Background(), testCase.input, testCase.dataSource, testCase.dataSourceSchema) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/internal/fromproto5/validateresourcetypeconfig.go b/internal/fromproto5/validateresourcetypeconfig.go index c36e4c6a9..ab454cc5c 100644 --- a/internal/fromproto5/validateresourcetypeconfig.go +++ b/internal/fromproto5/validateresourcetypeconfig.go @@ -6,13 +6,13 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-go/tfprotov5" ) // ValidateResourceTypeConfigRequest returns the *fwserver.ValidateResourceConfigRequest // equivalent of a *tfprotov5.ValidateResourceTypeConfigRequest. -func ValidateResourceTypeConfigRequest(ctx context.Context, proto5 *tfprotov5.ValidateResourceTypeConfigRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema) (*fwserver.ValidateResourceConfigRequest, diag.Diagnostics) { +func ValidateResourceTypeConfigRequest(ctx context.Context, proto5 *tfprotov5.ValidateResourceTypeConfigRequest, resource resource.Resource, resourceSchema fwschema.Schema) (*fwserver.ValidateResourceConfigRequest, diag.Diagnostics) { if proto5 == nil { return nil, nil } @@ -22,7 +22,7 @@ func ValidateResourceTypeConfigRequest(ctx context.Context, proto5 *tfprotov5.Va config, diags := Config(ctx, proto5.Config, resourceSchema) fw.Config = config - fw.ResourceType = resourceType + fw.Resource = resource return fw, diags } diff --git a/internal/fromproto5/validateresourcetypeconfig_test.go b/internal/fromproto5/validateresourcetypeconfig_test.go index 3683d1373..a417801de 100644 --- a/internal/fromproto5/validateresourcetypeconfig_test.go +++ b/internal/fromproto5/validateresourcetypeconfig_test.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fromproto5" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "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" "github.com/hashicorp/terraform-plugin-go/tfprotov5" @@ -47,7 +47,7 @@ func TestValidateResourceTypeConfigRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov5.ValidateResourceTypeConfigRequest resourceSchema fwschema.Schema - resourceType provider.ResourceType + resource resource.Resource expected *fwserver.ValidateResourceConfigRequest expectedDiagnostics diag.Diagnostics }{ @@ -94,7 +94,7 @@ func TestValidateResourceTypeConfigRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := fromproto5.ValidateResourceTypeConfigRequest(context.Background(), testCase.input, testCase.resourceType, testCase.resourceSchema) + got, diags := fromproto5.ValidateResourceTypeConfigRequest(context.Background(), testCase.input, testCase.resource, testCase.resourceSchema) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/internal/fromproto6/applyresourcechange.go b/internal/fromproto6/applyresourcechange.go index 47f843e06..45f7e7acf 100644 --- a/internal/fromproto6/applyresourcechange.go +++ b/internal/fromproto6/applyresourcechange.go @@ -9,12 +9,12 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" - "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/resource" ) // ApplyResourceChangeRequest returns the *fwserver.ApplyResourceChangeRequest // equivalent of a *tfprotov6.ApplyResourceChangeRequest. -func ApplyResourceChangeRequest(ctx context.Context, proto6 *tfprotov6.ApplyResourceChangeRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.ApplyResourceChangeRequest, diag.Diagnostics) { +func ApplyResourceChangeRequest(ctx context.Context, proto6 *tfprotov6.ApplyResourceChangeRequest, resource resource.Resource, resourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.ApplyResourceChangeRequest, diag.Diagnostics) { if proto6 == nil { return nil, nil } @@ -37,7 +37,7 @@ func ApplyResourceChangeRequest(ctx context.Context, proto6 *tfprotov6.ApplyReso fw := &fwserver.ApplyResourceChangeRequest{ ResourceSchema: resourceSchema, - ResourceType: resourceType, + Resource: resource, } config, configDiags := Config(ctx, proto6.Config, resourceSchema) diff --git a/internal/fromproto6/applyresourcechange_test.go b/internal/fromproto6/applyresourcechange_test.go index 88af00265..647172e9d 100644 --- a/internal/fromproto6/applyresourcechange_test.go +++ b/internal/fromproto6/applyresourcechange_test.go @@ -13,7 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" - "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" ) @@ -57,7 +57,7 @@ func TestApplyResourceChangeRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov6.ApplyResourceChangeRequest resourceSchema fwschema.Schema - resourceType provider.ResourceType + resource resource.Resource providerMetaSchema fwschema.Schema expected *fwserver.ApplyResourceChangeRequest expectedDiagnostics diag.Diagnostics @@ -253,7 +253,7 @@ func TestApplyResourceChangeRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := fromproto6.ApplyResourceChangeRequest(context.Background(), testCase.input, testCase.resourceType, testCase.resourceSchema, testCase.providerMetaSchema) + got, diags := fromproto6.ApplyResourceChangeRequest(context.Background(), testCase.input, testCase.resource, testCase.resourceSchema, testCase.providerMetaSchema) if diff := cmp.Diff(got, testCase.expected, cmp.AllowUnexported(privatestate.ProviderData{})); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/internal/fromproto6/importresourcestate.go b/internal/fromproto6/importresourcestate.go index 43cd03477..6d2114008 100644 --- a/internal/fromproto6/importresourcestate.go +++ b/internal/fromproto6/importresourcestate.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "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-go/tfprotov6" "github.com/hashicorp/terraform-plugin-go/tftypes" @@ -14,7 +14,7 @@ import ( // ImportResourceStateRequest returns the *fwserver.ImportResourceStateRequest // equivalent of a *tfprotov6.ImportResourceStateRequest. -func ImportResourceStateRequest(ctx context.Context, proto6 *tfprotov6.ImportResourceStateRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema) (*fwserver.ImportResourceStateRequest, diag.Diagnostics) { +func ImportResourceStateRequest(ctx context.Context, proto6 *tfprotov6.ImportResourceStateRequest, resource resource.Resource, resourceSchema fwschema.Schema) (*fwserver.ImportResourceStateRequest, diag.Diagnostics) { if proto6 == nil { return nil, nil } @@ -40,9 +40,9 @@ func ImportResourceStateRequest(ctx context.Context, proto6 *tfprotov6.ImportRes Raw: tftypes.NewValue(resourceSchema.Type().TerraformType(ctx), nil), Schema: tfsdkSchema(resourceSchema), }, - ID: proto6.ID, - ResourceType: resourceType, - TypeName: proto6.TypeName, + ID: proto6.ID, + Resource: resource, + TypeName: proto6.TypeName, } return fw, diags diff --git a/internal/fromproto6/importresourcestate_test.go b/internal/fromproto6/importresourcestate_test.go index 09061d6a3..a6e001654 100644 --- a/internal/fromproto6/importresourcestate_test.go +++ b/internal/fromproto6/importresourcestate_test.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fromproto6" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "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" "github.com/hashicorp/terraform-plugin-go/tfprotov6" @@ -36,7 +36,7 @@ func TestImportResourceStateRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov6.ImportResourceStateRequest resourceSchema fwschema.Schema - resourceType provider.ResourceType + resource resource.Resource expected *fwserver.ImportResourceStateRequest expectedDiagnostics diag.Diagnostics }{ @@ -92,7 +92,7 @@ func TestImportResourceStateRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := fromproto6.ImportResourceStateRequest(context.Background(), testCase.input, testCase.resourceType, testCase.resourceSchema) + got, diags := fromproto6.ImportResourceStateRequest(context.Background(), testCase.input, testCase.resource, testCase.resourceSchema) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/internal/fromproto6/planresourcechange.go b/internal/fromproto6/planresourcechange.go index bf7e18b60..3db72042b 100644 --- a/internal/fromproto6/planresourcechange.go +++ b/internal/fromproto6/planresourcechange.go @@ -9,12 +9,12 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" - "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/resource" ) // PlanResourceChangeRequest returns the *fwserver.PlanResourceChangeRequest // equivalent of a *tfprotov6.PlanResourceChangeRequest. -func PlanResourceChangeRequest(ctx context.Context, proto6 *tfprotov6.PlanResourceChangeRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.PlanResourceChangeRequest, diag.Diagnostics) { +func PlanResourceChangeRequest(ctx context.Context, proto6 *tfprotov6.PlanResourceChangeRequest, resource resource.Resource, resourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.PlanResourceChangeRequest, diag.Diagnostics) { if proto6 == nil { return nil, nil } @@ -37,7 +37,7 @@ func PlanResourceChangeRequest(ctx context.Context, proto6 *tfprotov6.PlanResour fw := &fwserver.PlanResourceChangeRequest{ ResourceSchema: resourceSchema, - ResourceType: resourceType, + Resource: resource, } config, configDiags := Config(ctx, proto6.Config, resourceSchema) diff --git a/internal/fromproto6/planresourcechange_test.go b/internal/fromproto6/planresourcechange_test.go index f15d680a5..46742fcca 100644 --- a/internal/fromproto6/planresourcechange_test.go +++ b/internal/fromproto6/planresourcechange_test.go @@ -13,7 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" - "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" ) @@ -55,7 +55,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov6.PlanResourceChangeRequest resourceSchema fwschema.Schema - resourceType provider.ResourceType + resource resource.Resource providerMetaSchema fwschema.Schema expected *fwserver.PlanResourceChangeRequest expectedDiagnostics diag.Diagnostics @@ -223,7 +223,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := fromproto6.PlanResourceChangeRequest(context.Background(), testCase.input, testCase.resourceType, testCase.resourceSchema, testCase.providerMetaSchema) + got, diags := fromproto6.PlanResourceChangeRequest(context.Background(), testCase.input, testCase.resource, testCase.resourceSchema, testCase.providerMetaSchema) if diff := cmp.Diff(got, testCase.expected, cmp.AllowUnexported(privatestate.ProviderData{})); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/internal/fromproto6/readdatasource.go b/internal/fromproto6/readdatasource.go index 4459fc59d..776c5864c 100644 --- a/internal/fromproto6/readdatasource.go +++ b/internal/fromproto6/readdatasource.go @@ -3,16 +3,16 @@ package fromproto6 import ( "context" + "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-go/tfprotov6" ) // ReadDataSourceRequest returns the *fwserver.ReadDataSourceRequest // equivalent of a *tfprotov6.ReadDataSourceRequest. -func ReadDataSourceRequest(ctx context.Context, proto6 *tfprotov6.ReadDataSourceRequest, dataSourceType provider.DataSourceType, dataSourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.ReadDataSourceRequest, diag.Diagnostics) { +func ReadDataSourceRequest(ctx context.Context, proto6 *tfprotov6.ReadDataSourceRequest, dataSource datasource.DataSource, dataSourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.ReadDataSourceRequest, diag.Diagnostics) { if proto6 == nil { return nil, nil } @@ -35,7 +35,7 @@ func ReadDataSourceRequest(ctx context.Context, proto6 *tfprotov6.ReadDataSource fw := &fwserver.ReadDataSourceRequest{ DataSourceSchema: dataSourceSchema, - DataSourceType: dataSourceType, + DataSource: dataSource, } config, configDiags := Config(ctx, proto6.Config, dataSourceSchema) diff --git a/internal/fromproto6/readdatasource_test.go b/internal/fromproto6/readdatasource_test.go index 778eebd22..9ed9e1a8a 100644 --- a/internal/fromproto6/readdatasource_test.go +++ b/internal/fromproto6/readdatasource_test.go @@ -5,11 +5,11 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fromproto6" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "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-go/tfprotov6" @@ -47,7 +47,7 @@ func TestReadDataSourceRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov6.ReadDataSourceRequest dataSourceSchema fwschema.Schema - dataSourceType provider.DataSourceType + dataSource datasource.DataSource providerMetaSchema fwschema.Schema expected *fwserver.ReadDataSourceRequest expectedDiagnostics diag.Diagnostics @@ -141,7 +141,7 @@ func TestReadDataSourceRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := fromproto6.ReadDataSourceRequest(context.Background(), testCase.input, testCase.dataSourceType, testCase.dataSourceSchema, testCase.providerMetaSchema) + got, diags := fromproto6.ReadDataSourceRequest(context.Background(), testCase.input, testCase.dataSource, testCase.dataSourceSchema, testCase.providerMetaSchema) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/internal/fromproto6/readresource.go b/internal/fromproto6/readresource.go index 6f6067371..a9f5f9a71 100644 --- a/internal/fromproto6/readresource.go +++ b/internal/fromproto6/readresource.go @@ -9,12 +9,12 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" - "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/resource" ) // ReadResourceRequest returns the *fwserver.ReadResourceRequest // equivalent of a *tfprotov6.ReadResourceRequest. -func ReadResourceRequest(ctx context.Context, proto6 *tfprotov6.ReadResourceRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.ReadResourceRequest, diag.Diagnostics) { +func ReadResourceRequest(ctx context.Context, proto6 *tfprotov6.ReadResourceRequest, resource resource.Resource, resourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.ReadResourceRequest, diag.Diagnostics) { if proto6 == nil { return nil, nil } @@ -22,7 +22,7 @@ func ReadResourceRequest(ctx context.Context, proto6 *tfprotov6.ReadResourceRequ var diags diag.Diagnostics fw := &fwserver.ReadResourceRequest{ - ResourceType: resourceType, + Resource: resource, } currentState, currentStateDiags := State(ctx, proto6.CurrentState, resourceSchema) diff --git a/internal/fromproto6/readresource_test.go b/internal/fromproto6/readresource_test.go index 6c9311f97..b8edbf166 100644 --- a/internal/fromproto6/readresource_test.go +++ b/internal/fromproto6/readresource_test.go @@ -13,7 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" - "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" ) @@ -57,7 +57,7 @@ func TestReadResourceRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov6.ReadResourceRequest resourceSchema fwschema.Schema - resourceType provider.ResourceType + resource resource.Resource providerMetaSchema fwschema.Schema expected *fwserver.ReadResourceRequest expectedDiagnostics diag.Diagnostics @@ -178,7 +178,7 @@ func TestReadResourceRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := fromproto6.ReadResourceRequest(context.Background(), testCase.input, testCase.resourceType, testCase.resourceSchema, testCase.providerMetaSchema) + got, diags := fromproto6.ReadResourceRequest(context.Background(), testCase.input, testCase.resource, testCase.resourceSchema, testCase.providerMetaSchema) if diff := cmp.Diff(got, testCase.expected, cmp.AllowUnexported(privatestate.ProviderData{})); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/internal/fromproto6/schema.go b/internal/fromproto6/schema.go index d926c3b8e..a5368aa31 100644 --- a/internal/fromproto6/schema.go +++ b/internal/fromproto6/schema.go @@ -14,6 +14,8 @@ import ( // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/366 func tfsdkSchema(s fwschema.Schema) tfsdk.Schema { switch s := s.(type) { + case tfsdk.Schema: + return s case *tfsdk.Schema: return *s default: diff --git a/internal/fromproto6/upgraderesourcestate.go b/internal/fromproto6/upgraderesourcestate.go index 0b9e034e9..f137cd27b 100644 --- a/internal/fromproto6/upgraderesourcestate.go +++ b/internal/fromproto6/upgraderesourcestate.go @@ -6,13 +6,13 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-go/tfprotov6" ) // UpgradeResourceStateRequest returns the *fwserver.UpgradeResourceStateRequest // equivalent of a *tfprotov6.UpgradeResourceStateRequest. -func UpgradeResourceStateRequest(ctx context.Context, proto6 *tfprotov6.UpgradeResourceStateRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema) (*fwserver.UpgradeResourceStateRequest, diag.Diagnostics) { +func UpgradeResourceStateRequest(ctx context.Context, proto6 *tfprotov6.UpgradeResourceStateRequest, resource resource.Resource, resourceSchema fwschema.Schema) (*fwserver.UpgradeResourceStateRequest, diag.Diagnostics) { if proto6 == nil { return nil, nil } @@ -36,7 +36,7 @@ func UpgradeResourceStateRequest(ctx context.Context, proto6 *tfprotov6.UpgradeR fw := &fwserver.UpgradeResourceStateRequest{ RawState: proto6.RawState, ResourceSchema: resourceSchema, - ResourceType: resourceType, + Resource: resource, Version: proto6.Version, } diff --git a/internal/fromproto6/upgraderesourcestate_test.go b/internal/fromproto6/upgraderesourcestate_test.go index 0366b0355..53df6ef42 100644 --- a/internal/fromproto6/upgraderesourcestate_test.go +++ b/internal/fromproto6/upgraderesourcestate_test.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fromproto6" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "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" "github.com/hashicorp/terraform-plugin-go/tfprotov6" @@ -30,7 +30,7 @@ func TestUpgradeResourceStateRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov6.UpgradeResourceStateRequest resourceSchema fwschema.Schema - resourceType provider.ResourceType + resource resource.Resource expected *fwserver.UpgradeResourceStateRequest expectedDiagnostics diag.Diagnostics }{ @@ -90,7 +90,7 @@ func TestUpgradeResourceStateRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := fromproto6.UpgradeResourceStateRequest(context.Background(), testCase.input, testCase.resourceType, testCase.resourceSchema) + got, diags := fromproto6.UpgradeResourceStateRequest(context.Background(), testCase.input, testCase.resource, testCase.resourceSchema) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/internal/fromproto6/validatedatasourceconfig.go b/internal/fromproto6/validatedatasourceconfig.go index adca93076..55b6656ca 100644 --- a/internal/fromproto6/validatedatasourceconfig.go +++ b/internal/fromproto6/validatedatasourceconfig.go @@ -3,16 +3,16 @@ package fromproto6 import ( "context" + "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-go/tfprotov6" ) // ValidateDataSourceConfigRequest returns the *fwserver.ValidateDataSourceConfigRequest // equivalent of a *tfprotov6.ValidateDataSourceConfigRequest. -func ValidateDataSourceConfigRequest(ctx context.Context, proto6 *tfprotov6.ValidateDataResourceConfigRequest, dataSourceType provider.DataSourceType, dataSourceSchema fwschema.Schema) (*fwserver.ValidateDataSourceConfigRequest, diag.Diagnostics) { +func ValidateDataSourceConfigRequest(ctx context.Context, proto6 *tfprotov6.ValidateDataResourceConfigRequest, dataSource datasource.DataSource, dataSourceSchema fwschema.Schema) (*fwserver.ValidateDataSourceConfigRequest, diag.Diagnostics) { if proto6 == nil { return nil, nil } @@ -22,7 +22,7 @@ func ValidateDataSourceConfigRequest(ctx context.Context, proto6 *tfprotov6.Vali config, diags := Config(ctx, proto6.Config, dataSourceSchema) fw.Config = config - fw.DataSourceType = dataSourceType + fw.DataSource = dataSource return fw, diags } diff --git a/internal/fromproto6/validatedatasourceconfig_test.go b/internal/fromproto6/validatedatasourceconfig_test.go index b21f9b73a..9a5311f41 100644 --- a/internal/fromproto6/validatedatasourceconfig_test.go +++ b/internal/fromproto6/validatedatasourceconfig_test.go @@ -5,11 +5,11 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fromproto6" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "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-go/tfprotov6" @@ -47,7 +47,7 @@ func TestValidateDataSourceConfigRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov6.ValidateDataResourceConfigRequest dataSourceSchema fwschema.Schema - dataSourceType provider.DataSourceType + dataSource datasource.DataSource expected *fwserver.ValidateDataSourceConfigRequest expectedDiagnostics diag.Diagnostics }{ @@ -94,7 +94,7 @@ func TestValidateDataSourceConfigRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := fromproto6.ValidateDataSourceConfigRequest(context.Background(), testCase.input, testCase.dataSourceType, testCase.dataSourceSchema) + got, diags := fromproto6.ValidateDataSourceConfigRequest(context.Background(), testCase.input, testCase.dataSource, testCase.dataSourceSchema) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/internal/fromproto6/validateresourceconfig.go b/internal/fromproto6/validateresourceconfig.go index 65c763f30..19a5cdd5b 100644 --- a/internal/fromproto6/validateresourceconfig.go +++ b/internal/fromproto6/validateresourceconfig.go @@ -6,13 +6,13 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-go/tfprotov6" ) // ValidateResourceConfigRequest returns the *fwserver.ValidateResourceConfigRequest // equivalent of a *tfprotov6.ValidateResourceConfigRequest. -func ValidateResourceConfigRequest(ctx context.Context, proto6 *tfprotov6.ValidateResourceConfigRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema) (*fwserver.ValidateResourceConfigRequest, diag.Diagnostics) { +func ValidateResourceConfigRequest(ctx context.Context, proto6 *tfprotov6.ValidateResourceConfigRequest, resource resource.Resource, resourceSchema fwschema.Schema) (*fwserver.ValidateResourceConfigRequest, diag.Diagnostics) { if proto6 == nil { return nil, nil } @@ -22,7 +22,7 @@ func ValidateResourceConfigRequest(ctx context.Context, proto6 *tfprotov6.Valida config, diags := Config(ctx, proto6.Config, resourceSchema) fw.Config = config - fw.ResourceType = resourceType + fw.Resource = resource return fw, diags } diff --git a/internal/fromproto6/validateresourceconfig_test.go b/internal/fromproto6/validateresourceconfig_test.go index 7b834b985..a423ee0cf 100644 --- a/internal/fromproto6/validateresourceconfig_test.go +++ b/internal/fromproto6/validateresourceconfig_test.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fromproto6" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" - "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" "github.com/hashicorp/terraform-plugin-go/tfprotov6" @@ -47,7 +47,7 @@ func TestValidateResourceConfigRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov6.ValidateResourceConfigRequest resourceSchema fwschema.Schema - resourceType provider.ResourceType + resource resource.Resource expected *fwserver.ValidateResourceConfigRequest expectedDiagnostics diag.Diagnostics }{ @@ -94,7 +94,7 @@ func TestValidateResourceConfigRequest(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got, diags := fromproto6.ValidateResourceConfigRequest(context.Background(), testCase.input, testCase.resourceType, testCase.resourceSchema) + got, diags := fromproto6.ValidateResourceConfigRequest(context.Background(), testCase.input, testCase.resource, testCase.resourceSchema) if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/internal/fwserver/server.go b/internal/fwserver/server.go index b9b227db5..85e73bcd5 100644 --- a/internal/fwserver/server.go +++ b/internal/fwserver/server.go @@ -5,10 +5,12 @@ import ( "fmt" "sync" + "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/resource" ) // Server implements the framework provider server. Protocol specific @@ -17,6 +19,16 @@ import ( type Server struct { Provider provider.Provider + // DataSourceConfigureData is the + // [provider.ConfigureResponse.DataSourceData] field value which is passed + // to [datasource.ConfigureRequest.ProviderData]. + DataSourceConfigureData any + + // ResourceConfigureData is the + // [provider.ConfigureResponse.ResourceData] field value which is passed + // to [resource.ConfigureRequest.ProviderData]. + ResourceConfigureData any + // dataSourceSchemas is the cached DataSource Schemas for RPCs that need to // convert configuration data from the protocol. If not found, it will be // fetched from the DataSourceType.GetSchema() method. @@ -31,9 +43,15 @@ type Server struct { // access from race conditions. dataSourceSchemasMutex sync.Mutex + // dataSourceFuncs is the cached DataSource functions for RPCs that need to + // access data sources. If not found, it will be fetched from the + // Provider.DataSources() method. + dataSourceFuncs map[string]func() datasource.DataSource + // dataSourceTypes is the cached DataSourceTypes for RPCs that need to // access data sources. If not found, it will be fetched from the // Provider.GetDataSources() method. + //nolint:staticcheck // Internal implementation dataSourceTypes map[string]provider.DataSourceType // dataSourceTypesDiags is the cached Diagnostics obtained while populating @@ -73,6 +91,10 @@ type Server struct { // access from race conditions. providerMetaSchemaMutex sync.Mutex + // providerTypeName is the type name of the provider, if the provider + // implemented the Metadata method. + providerTypeName string + // resourceSchemas is the cached Resource Schemas for RPCs that need to // convert configuration data from the protocol. If not found, it will be // fetched from the ResourceType.GetSchema() method. @@ -87,9 +109,15 @@ type Server struct { // access from race conditions. resourceSchemasMutex sync.Mutex + // resourceFuncs is the cached Resource functions for RPCs that need to + // access resources. If not found, it will be fetched from the + // Provider.Resources() method. + resourceFuncs map[string]func() resource.Resource + // resourceTypes is the cached ResourceTypes for RPCs that need to // access resources. If not found, it will be fetched from the // Provider.GetResources() method. + //nolint:staticcheck // Internal implementation resourceTypes map[string]provider.ResourceType // resourceTypesDiags is the cached Diagnostics obtained while populating @@ -102,6 +130,107 @@ type Server struct { resourceTypesMutex sync.Mutex } +// DataSource returns the DataSource for a given type name. +func (s *Server) DataSource(ctx context.Context, typeName string) (datasource.DataSource, diag.Diagnostics) { + dataSourceFuncs, diags := s.DataSourceFuncs(ctx) + + dataSourceFunc, ok := dataSourceFuncs[typeName] + + if ok { + return dataSourceFunc(), diags + } + + dataSourceTypes, diags := s.DataSourceTypes(ctx) + + dataSourceType, ok := dataSourceTypes[typeName] + + if !ok { + diags.AddError( + "Data Source Type Not Found", + fmt.Sprintf("No data source type named %q was found in the provider.", typeName), + ) + + return nil, diags + } + + logging.FrameworkDebug(ctx, "Calling provider defined DataSourceType NewDataSource") + dataSource, diags := dataSourceType.NewDataSource(ctx, s.Provider) + logging.FrameworkDebug(ctx, "Called provider defined DataSourceType NewDataSource") + + return dataSource, diags +} + +// DataSourceFuncs returns a map of DataSource functions. The results are cached +// on first use. +func (s *Server) DataSourceFuncs(ctx context.Context) (map[string]func() datasource.DataSource, diag.Diagnostics) { + logging.FrameworkTrace(ctx, "Checking DataSourceTypes lock") + s.dataSourceTypesMutex.Lock() + defer s.dataSourceTypesMutex.Unlock() + + if s.dataSourceFuncs != nil { + return s.dataSourceFuncs, s.dataSourceTypesDiags + } + + s.dataSourceFuncs = make(map[string]func() datasource.DataSource) + + providerWithDataSources, ok := s.Provider.(provider.ProviderWithDataSources) + + if !ok { + return s.dataSourceFuncs, nil + } + + logging.FrameworkDebug(ctx, "Calling provider defined Provider DataSources") + dataSourceFuncsSlice := providerWithDataSources.DataSources(ctx) + logging.FrameworkDebug(ctx, "Called provider defined Provider DataSources") + + for _, dataSourceFunc := range dataSourceFuncsSlice { + dataSource := dataSourceFunc() + + dataSourceWithMetadata, ok := dataSource.(datasource.DataSourceWithMetadata) + + if !ok { + s.dataSourceTypesDiags.AddError( + "Data Source Type Name Missing", + fmt.Sprintf("The %T DataSource in the provider DataSources method results is missing the Metadata method. ", dataSource)+ + "This is always an issue with the provider and should be reported to the provider developers.", + ) + continue + } + + dataSourceTypeNameReq := datasource.MetadataRequest{ + ProviderTypeName: s.providerTypeName, + } + dataSourceTypeNameResp := datasource.MetadataResponse{} + + dataSourceWithMetadata.Metadata(ctx, dataSourceTypeNameReq, &dataSourceTypeNameResp) + + if dataSourceTypeNameResp.TypeName == "" { + s.dataSourceTypesDiags.AddError( + "Data Source Type Name Missing", + fmt.Sprintf("The %T DataSource returned an empty string from the Metadata method. ", dataSource)+ + "This is always an issue with the provider and should be reported to the provider developers.", + ) + continue + } + + logging.FrameworkTrace(ctx, "Found data source type", map[string]interface{}{logging.KeyDataSourceType: dataSourceTypeNameResp.TypeName}) + + if _, ok := s.dataSourceFuncs[dataSourceTypeNameResp.TypeName]; ok { + s.dataSourceTypesDiags.AddError( + "Duplicate Data Source Type Defined", + fmt.Sprintf("The %s data source type name was returned for multiple data sources. ", dataSourceTypeNameResp.TypeName)+ + "Data source type names must be unique. "+ + "This is always an issue with the provider and should be reported to the provider developers.", + ) + continue + } + + s.dataSourceFuncs[dataSourceTypeNameResp.TypeName] = dataSourceFunc + } + + return s.dataSourceFuncs, s.dataSourceTypesDiags +} + // DataSourceSchema returns the Schema associated with the DataSourceType for // the given type name. func (s *Server) DataSourceSchema(ctx context.Context, typeName string) (fwschema.Schema, diag.Diagnostics) { @@ -133,9 +262,45 @@ func (s *Server) DataSourceSchemas(ctx context.Context) (map[string]fwschema.Sch return s.dataSourceSchemas, s.dataSourceSchemasDiags } + s.dataSourceSchemas = map[string]fwschema.Schema{} + + dataSourceFuncs, diags := s.DataSourceFuncs(ctx) + + s.dataSourceSchemasDiags = diags + + for dataSourceTypeName, dataSourceFunc := range dataSourceFuncs { + dataSource := dataSourceFunc() + + dataSourceWithGetSchema, ok := dataSource.(datasource.DataSourceWithGetSchema) + + if !ok { + s.dataSourceSchemasDiags.AddError( + "Data Source Schema Missing", + fmt.Sprintf("The %T DataSource in the provider is missing the GetSchema method. ", dataSource)+ + "This is always an issue with the provider and should be reported to the provider developers.", + ) + continue + } + + logging.FrameworkDebug(ctx, "Calling provider defined DataSource GetSchema", map[string]interface{}{logging.KeyDataSourceType: dataSourceTypeName}) + schema, diags := dataSourceWithGetSchema.GetSchema(ctx) + logging.FrameworkDebug(ctx, "Called provider defined DataSource GetSchema", map[string]interface{}{logging.KeyDataSourceType: dataSourceTypeName}) + + s.dataSourceSchemasDiags.Append(diags...) + + if s.dataSourceSchemasDiags.HasError() { + return s.dataSourceSchemas, s.dataSourceSchemasDiags + } + + s.dataSourceSchemas[dataSourceTypeName] = schema + } + + if len(s.dataSourceSchemas) > 0 || s.dataSourceSchemasDiags.HasError() { + return s.dataSourceSchemas, s.dataSourceSchemasDiags + } + dataSourceTypes, diags := s.DataSourceTypes(ctx) - s.dataSourceSchemas = map[string]fwschema.Schema{} s.dataSourceSchemasDiags = diags if s.dataSourceSchemasDiags.HasError() { @@ -161,26 +326,10 @@ func (s *Server) DataSourceSchemas(ctx context.Context) (map[string]fwschema.Sch return s.dataSourceSchemas, s.dataSourceSchemasDiags } -// DataSourceType returns the DataSourceType for a given type name. -func (s *Server) DataSourceType(ctx context.Context, typeName string) (provider.DataSourceType, diag.Diagnostics) { - dataSourceTypes, diags := s.DataSourceTypes(ctx) - - dataSourceType, ok := dataSourceTypes[typeName] - - if !ok { - diags.AddError( - "Data Source Type Not Found", - fmt.Sprintf("No data source type named %q was found in the provider.", typeName), - ) - - return nil, diags - } - - return dataSourceType, diags -} - // DataSourceTypes returns the map of DataSourceTypes. The results are cached // on first use. +// +//nolint:staticcheck // Internal implementation func (s *Server) DataSourceTypes(ctx context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { logging.FrameworkTrace(ctx, "Checking DataSourceTypes lock") s.dataSourceTypesMutex.Lock() @@ -190,8 +339,16 @@ func (s *Server) DataSourceTypes(ctx context.Context) (map[string]provider.DataS return s.dataSourceTypes, s.dataSourceTypesDiags } + s.dataSourceTypes = make(map[string]provider.DataSourceType) + + providerWithGetDataSources, ok := s.Provider.(provider.ProviderWithGetDataSources) //nolint:staticcheck // Internal usage + + if !ok { + return s.dataSourceTypes, nil + } + logging.FrameworkDebug(ctx, "Calling provider defined Provider GetDataSources") - s.dataSourceTypes, s.dataSourceTypesDiags = s.Provider.GetDataSources(ctx) + s.dataSourceTypes, s.dataSourceTypesDiags = providerWithGetDataSources.GetDataSources(ctx) //nolint:staticcheck // Internal usage logging.FrameworkDebug(ctx, "Called provider defined Provider GetDataSources") return s.dataSourceTypes, s.dataSourceTypesDiags @@ -247,6 +404,107 @@ func (s *Server) ProviderMetaSchema(ctx context.Context) (fwschema.Schema, diag. return s.providerMetaSchema, s.providerMetaSchemaDiags } +// Resource returns the Resource for a given type name. +func (s *Server) Resource(ctx context.Context, typeName string) (resource.Resource, diag.Diagnostics) { + resourceFuncs, diags := s.ResourceFuncs(ctx) + + resourceFunc, ok := resourceFuncs[typeName] + + if ok { + return resourceFunc(), diags + } + + resourceTypes, diags := s.ResourceTypes(ctx) + + resourceType, ok := resourceTypes[typeName] + + if !ok { + diags.AddError( + "Resource Type Not Found", + fmt.Sprintf("No resource type named %q was found in the provider.", typeName), + ) + + return nil, diags + } + + logging.FrameworkDebug(ctx, "Calling provider defined ResourceType NewResource") + resource, diags := resourceType.NewResource(ctx, s.Provider) + logging.FrameworkDebug(ctx, "Called provider defined ResourceType NewResource") + + return resource, diags +} + +// ResourceFuncs returns a map of Resource functions. The results are cached +// on first use. +func (s *Server) ResourceFuncs(ctx context.Context) (map[string]func() resource.Resource, diag.Diagnostics) { + logging.FrameworkTrace(ctx, "Checking ResourceTypes lock") + s.resourceTypesMutex.Lock() + defer s.resourceTypesMutex.Unlock() + + if s.resourceFuncs != nil { + return s.resourceFuncs, s.resourceTypesDiags + } + + s.resourceFuncs = make(map[string]func() resource.Resource) + + providerWithResources, ok := s.Provider.(provider.ProviderWithResources) + + if !ok { + return s.resourceFuncs, nil + } + + logging.FrameworkDebug(ctx, "Calling provider defined Provider Resources") + resourceFuncsSlice := providerWithResources.Resources(ctx) + logging.FrameworkDebug(ctx, "Called provider defined Provider Resources") + + for _, resourceFunc := range resourceFuncsSlice { + res := resourceFunc() + + resourceWithMetadata, ok := res.(resource.ResourceWithMetadata) + + if !ok { + s.resourceTypesDiags.AddError( + "Resource Type Name Missing", + fmt.Sprintf("The %T Resource in the provider Resources method results is missing the Metadata method. ", res)+ + "This is always an issue with the provider and should be reported to the provider developers.", + ) + continue + } + + resourceTypeNameReq := resource.MetadataRequest{ + ProviderTypeName: s.providerTypeName, + } + resourceTypeNameResp := resource.MetadataResponse{} + + resourceWithMetadata.Metadata(ctx, resourceTypeNameReq, &resourceTypeNameResp) + + if resourceTypeNameResp.TypeName == "" { + s.resourceTypesDiags.AddError( + "Resource Type Name Missing", + fmt.Sprintf("The %T Resource returned an empty string from the Metadata method. ", res)+ + "This is always an issue with the provider and should be reported to the provider developers.", + ) + continue + } + + logging.FrameworkTrace(ctx, "Found resource type", map[string]interface{}{logging.KeyResourceType: resourceTypeNameResp.TypeName}) + + if _, ok := s.resourceFuncs[resourceTypeNameResp.TypeName]; ok { + s.resourceTypesDiags.AddError( + "Duplicate Resource Type Defined", + fmt.Sprintf("The %s resource type name was returned for multiple resources. ", resourceTypeNameResp.TypeName)+ + "Resource type names must be unique. "+ + "This is always an issue with the provider and should be reported to the provider developers.", + ) + continue + } + + s.resourceFuncs[resourceTypeNameResp.TypeName] = resourceFunc + } + + return s.resourceFuncs, s.resourceTypesDiags +} + // ResourceSchema returns the Schema associated with the ResourceType for // the given type name. func (s *Server) ResourceSchema(ctx context.Context, typeName string) (fwschema.Schema, diag.Diagnostics) { @@ -278,9 +536,45 @@ func (s *Server) ResourceSchemas(ctx context.Context) (map[string]fwschema.Schem return s.resourceSchemas, s.resourceSchemasDiags } + s.resourceSchemas = map[string]fwschema.Schema{} + + resourceFuncs, diags := s.ResourceFuncs(ctx) + + s.resourceSchemasDiags = diags + + for resourceTypeName, resourceFunc := range resourceFuncs { + res := resourceFunc() + + resourceWithGetSchema, ok := res.(resource.ResourceWithGetSchema) + + if !ok { + s.resourceSchemasDiags.AddError( + "Resource Schema Missing", + fmt.Sprintf("The %T Resource in the provider is missing the GetSchema method. ", res)+ + "This is always an issue with the provider and should be reported to the provider developers.", + ) + continue + } + + logging.FrameworkDebug(ctx, "Calling provider defined Resource GetSchema", map[string]interface{}{logging.KeyResourceType: resourceTypeName}) + schema, diags := resourceWithGetSchema.GetSchema(ctx) + logging.FrameworkDebug(ctx, "Called provider defined Resource GetSchema", map[string]interface{}{logging.KeyResourceType: resourceTypeName}) + + s.resourceSchemasDiags.Append(diags...) + + if s.resourceSchemasDiags.HasError() { + return s.resourceSchemas, s.resourceSchemasDiags + } + + s.resourceSchemas[resourceTypeName] = schema + } + + if len(s.resourceSchemas) > 0 || s.resourceSchemasDiags.HasError() { + return s.resourceSchemas, s.resourceSchemasDiags + } + resourceTypes, diags := s.ResourceTypes(ctx) - s.resourceSchemas = map[string]fwschema.Schema{} s.resourceSchemasDiags = diags if s.resourceSchemasDiags.HasError() { @@ -306,26 +600,10 @@ func (s *Server) ResourceSchemas(ctx context.Context) (map[string]fwschema.Schem return s.resourceSchemas, s.resourceSchemasDiags } -// ResourceType returns the ResourceType for a given type name. -func (s *Server) ResourceType(ctx context.Context, typeName string) (provider.ResourceType, diag.Diagnostics) { - resourceTypes, diags := s.ResourceTypes(ctx) - - resourceType, ok := resourceTypes[typeName] - - if !ok { - diags.AddError( - "Resource Type Not Found", - fmt.Sprintf("No resource type named %q was found in the provider.", typeName), - ) - - return nil, diags - } - - return resourceType, diags -} - // ResourceTypes returns the map of ResourceTypes. The results are cached // on first use. +// +//nolint:staticcheck // Internal implementation func (s *Server) ResourceTypes(ctx context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { logging.FrameworkTrace(ctx, "Checking ResourceTypes lock") s.resourceTypesMutex.Lock() @@ -335,8 +613,16 @@ func (s *Server) ResourceTypes(ctx context.Context) (map[string]provider.Resourc return s.resourceTypes, s.resourceTypesDiags } + s.resourceTypes = make(map[string]provider.ResourceType) + + providerWithGetResources, ok := s.Provider.(provider.ProviderWithGetResources) //nolint:staticcheck // Internal usage + + if !ok { + return s.resourceTypes, nil + } + logging.FrameworkDebug(ctx, "Calling provider defined Provider GetResources") - s.resourceTypes, s.resourceTypesDiags = s.Provider.GetResources(ctx) + s.resourceTypes, s.resourceTypesDiags = providerWithGetResources.GetResources(ctx) //nolint:staticcheck // Internal usage logging.FrameworkDebug(ctx, "Called provider defined Provider GetResources") return s.resourceTypes, s.resourceTypesDiags diff --git a/internal/fwserver/server_applyresourcechange.go b/internal/fwserver/server_applyresourcechange.go index 8f2069049..ef9c5ab4b 100644 --- a/internal/fwserver/server_applyresourcechange.go +++ b/internal/fwserver/server_applyresourcechange.go @@ -7,7 +7,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" - "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/tfsdk" ) @@ -20,7 +20,7 @@ type ApplyResourceChangeRequest struct { PriorState *tfsdk.State ProviderMeta *tfsdk.Config ResourceSchema fwschema.Schema - ResourceType provider.ResourceType + Resource resource.Resource } // ApplyResourceChangeResponse is the framework server response for the @@ -47,7 +47,7 @@ func (s *Server) ApplyResourceChange(ctx context.Context, req *ApplyResourceChan PlannedState: req.PlannedState, ProviderMeta: req.ProviderMeta, ResourceSchema: req.ResourceSchema, - ResourceType: req.ResourceType, + Resource: req.Resource, } createResp := &CreateResourceResponse{} @@ -69,7 +69,7 @@ func (s *Server) ApplyResourceChange(ctx context.Context, req *ApplyResourceChan PriorState: req.PriorState, ProviderMeta: req.ProviderMeta, ResourceSchema: req.ResourceSchema, - ResourceType: req.ResourceType, + Resource: req.Resource, } deleteResp := &DeleteResourceResponse{} @@ -92,7 +92,7 @@ func (s *Server) ApplyResourceChange(ctx context.Context, req *ApplyResourceChan PriorState: req.PriorState, ProviderMeta: req.ProviderMeta, ResourceSchema: req.ResourceSchema, - ResourceType: req.ResourceType, + Resource: req.Resource, } updateResp := &UpdateResourceResponse{} diff --git a/internal/fwserver/server_applyresourcechange_test.go b/internal/fwserver/server_applyresourcechange_test.go index 1095d3451..195962a5e 100644 --- a/internal/fwserver/server_applyresourcechange_test.go +++ b/internal/fwserver/server_applyresourcechange_test.go @@ -13,7 +13,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" - "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" @@ -133,31 +132,24 @@ func TestServerApplyResourceChange(t *testing.T) { }, PriorState: testEmptyState, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - var data testSchemaData + Resource: &testprovider.Resource{ + CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - if data.TestRequired.Value != "test-config-value" { - resp.Diagnostics.AddError("unexpected req.Config value: %s", data.TestRequired.Value) - } + if data.TestRequired.Value != "test-config-value" { + resp.Diagnostics.AddError("unexpected req.Config value: %s", data.TestRequired.Value) + } - // Prevent missing resource state error diagnostic - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) - }, - DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Delete") - }, - UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") - }, - }, nil + // Prevent missing resource state error diagnostic + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + }, + DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Delete") + }, + UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, }, }, @@ -186,31 +178,24 @@ func TestServerApplyResourceChange(t *testing.T) { }, PriorState: testEmptyState, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - var data testSchemaData + Resource: &testprovider.Resource{ + CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - if data.TestRequired.Value != "test-plannedstate-value" { - resp.Diagnostics.AddError("unexpected req.Plan value: %s", data.TestRequired.Value) - } + if data.TestRequired.Value != "test-plannedstate-value" { + resp.Diagnostics.AddError("unexpected req.Plan value: %s", data.TestRequired.Value) + } - // Prevent missing resource state error diagnostic - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) - }, - DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Delete") - }, - UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") - }, - }, nil + // Prevent missing resource state error diagnostic + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + }, + DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Delete") + }, + UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, }, }, @@ -238,34 +223,27 @@ func TestServerApplyResourceChange(t *testing.T) { }, PriorState: testEmptyState, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - var metadata testProviderMetaData + Resource: &testprovider.Resource{ + CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var metadata testProviderMetaData - resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &metadata)...) + resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &metadata)...) - if metadata.TestProviderMetaAttribute.Value != "test-provider-meta-value" { - resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+metadata.TestProviderMetaAttribute.Value) - } + if metadata.TestProviderMetaAttribute.Value != "test-provider-meta-value" { + resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+metadata.TestProviderMetaAttribute.Value) + } - // Prevent missing resource state error diagnostic - var data testSchemaData + // Prevent missing resource state error diagnostic + var data testSchemaData - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) - }, - DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Delete") - }, - UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") - }, - }, nil + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + }, + DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Delete") + }, + UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, }, ProviderMeta: testProviderMetaConfig, @@ -288,23 +266,16 @@ func TestServerApplyResourceChange(t *testing.T) { request: &fwserver.ApplyResourceChangeRequest{ PriorState: testEmptyState, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Delete") - }, - UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") - }, - }, nil + Resource: &testprovider.Resource{ + CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") + }, + DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Delete") + }, + UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, }, }, @@ -345,25 +316,18 @@ func TestServerApplyResourceChange(t *testing.T) { }, PriorState: testEmptyState, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - var data testSchemaData + Resource: &testprovider.Resource{ + CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) - }, - DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Delete") - }, - UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") - }, - }, nil + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + }, + DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Delete") + }, + UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, }, }, @@ -399,22 +363,15 @@ func TestServerApplyResourceChange(t *testing.T) { }, PriorState: testEmptyState, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil + Resource: &testprovider.Resource{ + CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + // Intentionally missing resp.State.Set() + }, + DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Delete") }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - // Intentionally missing resp.State.Set() - }, - DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Delete") - }, - UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") - }, - }, nil + UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, }, }, @@ -439,29 +396,22 @@ func TestServerApplyResourceChange(t *testing.T) { request: &fwserver.ApplyResourceChangeRequest{ PriorState: testEmptyState, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - var data testSchemaData + Resource: &testprovider.Resource{ + CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data testSchemaData - // Prevent missing resource state error diagnostic - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + // Prevent missing resource state error diagnostic + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) - diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) + diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) - resp.Diagnostics.Append(diags...) - }, - DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Delete") - }, - UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") - }, - }, nil + resp.Diagnostics.Append(diags...) + }, + DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Delete") + }, + UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, }, }, @@ -492,28 +442,21 @@ func TestServerApplyResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil + Resource: &testprovider.Resource{ + CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") - }, - DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - var data testSchemaData + DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) - if data.TestRequired.Value != "test-priorstate-value" { - resp.Diagnostics.AddError("unexpected req.State value: %s", data.TestRequired.Value) - } - }, - UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") - }, - }, nil + if data.TestRequired.Value != "test-priorstate-value" { + resp.Diagnostics.AddError("unexpected req.State value: %s", data.TestRequired.Value) + } + }, + UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") }, }, }, @@ -535,28 +478,21 @@ func TestServerApplyResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") - }, - DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - var data testProviderMetaData - - resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) - - if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { - resp.Diagnostics.AddError("unexpected req.ProviderMeta value: %s", data.TestProviderMetaAttribute.Value) - } - }, - UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") - }, - }, nil + Resource: &testprovider.Resource{ + CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") + }, + DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data testProviderMetaData + + resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) + + if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { + resp.Diagnostics.AddError("unexpected req.ProviderMeta value: %s", data.TestProviderMetaAttribute.Value) + } + }, + UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") }, }, ProviderMeta: testProviderMetaConfig, @@ -578,32 +514,25 @@ func TestServerApplyResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") - }, - DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` - got, diags := req.Private.GetKey(ctx, "providerKeyOne") - - resp.Diagnostics.Append(diags...) - - if string(got) != expected { - resp.Diagnostics.AddError( - "Unexpected req.Private Value", - fmt.Sprintf("expected %q, got %q", expected, got), - ) - } - }, - UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") - }, - }, nil + Resource: &testprovider.Resource{ + CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") + }, + DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` + got, diags := req.Private.GetKey(ctx, "providerKeyOne") + + resp.Diagnostics.Append(diags...) + + if string(got) != expected { + resp.Diagnostics.AddError( + "Unexpected req.Private Value", + fmt.Sprintf("expected %q, got %q", expected, got), + ) + } + }, + UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") }, }, PlannedPrivate: &privatestate.Data{ @@ -627,33 +556,26 @@ func TestServerApplyResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil + Resource: &testprovider.Resource{ + CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") - }, - DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - var expected []byte + DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var expected []byte - got, diags := req.Private.GetKey(ctx, "providerKeyOne") + got, diags := req.Private.GetKey(ctx, "providerKeyOne") - resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(diags...) - if !bytes.Equal(got, expected) { - resp.Diagnostics.AddError( - "Unexpected req.Private Value", - fmt.Sprintf("expected %q, got %q", expected, got), - ) - } - }, - UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") - }, - }, nil + if !bytes.Equal(got, expected) { + resp.Diagnostics.AddError( + "Unexpected req.Private Value", + fmt.Sprintf("expected %q, got %q", expected, got), + ) + } + }, + UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") }, }, }, @@ -675,23 +597,16 @@ func TestServerApplyResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") - }, - DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") - }, - }, nil + Resource: &testprovider.Resource{ + CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") + }, + DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") + }, + UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") }, }, }, @@ -729,22 +644,15 @@ func TestServerApplyResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil + Resource: &testprovider.Resource{ + CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") + }, + DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + // Intentionally empty, should call resp.State.RemoveResource() automatically. }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") - }, - DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - // Intentionally empty, should call resp.State.RemoveResource() automatically. - }, - UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") - }, - }, nil + UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") }, }, }, @@ -779,28 +687,21 @@ func TestServerApplyResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil + Resource: &testprovider.Resource{ + CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") - }, - DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") - }, - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var data testSchemaData + DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") + }, + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - if data.TestRequired.Value != "test-new-value" { - resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) - } - }, - }, nil + if data.TestRequired.Value != "test-new-value" { + resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) + } }, }, }, @@ -843,28 +744,21 @@ func TestServerApplyResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil + Resource: &testprovider.Resource{ + CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") + }, + DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") - }, - DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") - }, - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var data testSchemaData + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - if data.TestComputed.Value != "test-plannedstate-value" { - resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestComputed.Value) - } - }, - }, nil + if data.TestComputed.Value != "test-plannedstate-value" { + resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestComputed.Value) + } }, }, }, @@ -907,28 +801,21 @@ func TestServerApplyResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil + Resource: &testprovider.Resource{ + CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") + }, + DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") - }, - DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") - }, - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var data testSchemaData + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) - if data.TestRequired.Value != "test-old-value" { - resp.Diagnostics.AddError("Unexpected req.State Value", "Got: "+data.TestRequired.Value) - } - }, - }, nil + if data.TestRequired.Value != "test-old-value" { + resp.Diagnostics.AddError("Unexpected req.State Value", "Got: "+data.TestRequired.Value) + } }, }, }, @@ -972,28 +859,21 @@ func TestServerApplyResourceChange(t *testing.T) { }, ProviderMeta: testProviderMetaConfig, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil + Resource: &testprovider.Resource{ + CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") - }, - DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") - }, - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var data testProviderMetaData + DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") + }, + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data testProviderMetaData - resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) + resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) - if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { - resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) - } - }, - }, nil + if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { + resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) + } }, }, }, @@ -1029,32 +909,25 @@ func TestServerApplyResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") - }, - DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") - }, - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` - got, diags := req.Private.GetKey(ctx, "providerKeyOne") - - resp.Diagnostics.Append(diags...) - - if string(got) != expected { - resp.Diagnostics.AddError( - "Unexpected req.Private Value", - fmt.Sprintf("expected %q, got %q", expected, got), - ) - } - }, - }, nil + Resource: &testprovider.Resource{ + CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") + }, + DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") + }, + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` + got, diags := req.Private.GetKey(ctx, "providerKeyOne") + + resp.Diagnostics.Append(diags...) + + if string(got) != expected { + resp.Diagnostics.AddError( + "Unexpected req.Private Value", + fmt.Sprintf("expected %q, got %q", expected, got), + ) + } }, }, PlannedPrivate: testPrivateProvider, @@ -1093,32 +966,25 @@ func TestServerApplyResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") - }, - DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") - }, - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var expected []byte - got, diags := req.Private.GetKey(ctx, "providerKeyOne") - - resp.Diagnostics.Append(diags...) - - if !bytes.Equal(got, expected) { - resp.Diagnostics.AddError( - "Unexpected req.Private Value", - fmt.Sprintf("expected %q, got %q", expected, got), - ) - } - }, - }, nil + Resource: &testprovider.Resource{ + CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") + }, + DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") + }, + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var expected []byte + got, diags := req.Private.GetKey(ctx, "providerKeyOne") + + resp.Diagnostics.Append(diags...) + + if !bytes.Equal(got, expected) { + resp.Diagnostics.AddError( + "Unexpected req.Private Value", + fmt.Sprintf("expected %q, got %q", expected, got), + ) + } }, }, }, @@ -1161,23 +1027,16 @@ func TestServerApplyResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") - }, - DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") - }, - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil + Resource: &testprovider.Resource{ + CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") + }, + DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") + }, + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") }, }, }, @@ -1229,25 +1088,18 @@ func TestServerApplyResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil + Resource: &testprovider.Resource{ + CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") + }, + DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") - }, - DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") - }, - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var data testSchemaData + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) - }, - }, nil + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) }, }, }, @@ -1289,22 +1141,15 @@ func TestServerApplyResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil + Resource: &testprovider.Resource{ + CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") - }, - DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") - }, - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.State.RemoveResource(ctx) - }, - }, nil + DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") + }, + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.State.RemoveResource(ctx) }, }, }, @@ -1340,24 +1185,17 @@ func TestServerApplyResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil + Resource: &testprovider.Resource{ + CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") + }, + DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") - }, - DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") - }, - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) - resp.Diagnostics.Append(diags...) - }, - }, nil + resp.Diagnostics.Append(diags...) }, }, }, @@ -1392,24 +1230,17 @@ func TestServerApplyResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") - }, - DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") - }, - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) - - resp.Diagnostics.Append(diags...) - }, - }, nil + Resource: &testprovider.Resource{ + CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") + }, + DeleteMethod: func(_ context.Context, _ resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Delete") + }, + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) + + resp.Diagnostics.Append(diags...) }, }, PlannedPrivate: testPrivateFramework, diff --git a/internal/fwserver/server_configureprovider.go b/internal/fwserver/server_configureprovider.go index 07d526561..059300e8e 100644 --- a/internal/fwserver/server_configureprovider.go +++ b/internal/fwserver/server_configureprovider.go @@ -18,4 +18,7 @@ func (s *Server) ConfigureProvider(ctx context.Context, req *provider.ConfigureR } logging.FrameworkDebug(ctx, "Called provider defined Provider Configure") + + s.DataSourceConfigureData = resp.DataSourceData + s.ResourceConfigureData = resp.ResourceData } diff --git a/internal/fwserver/server_configureprovider_test.go b/internal/fwserver/server_configureprovider_test.go index 445e3c528..43b0ac4af 100644 --- a/internal/fwserver/server_configureprovider_test.go +++ b/internal/fwserver/server_configureprovider_test.go @@ -97,6 +97,22 @@ func TestServerConfigureProvider(t *testing.T) { }, expectedResponse: &provider.ConfigureResponse{}, }, + "response-datasourcedata": { + server: &fwserver.Server{ + Provider: &testprovider.Provider{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{}, nil + }, + ConfigureMethod: func(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { + resp.DataSourceData = "test-provider-configure-value" + }, + }, + }, + request: &provider.ConfigureRequest{}, + expectedResponse: &provider.ConfigureResponse{ + DataSourceData: "test-provider-configure-value", + }, + }, "response-diagnostics": { server: &fwserver.Server{ Provider: &testprovider.Provider{ @@ -123,6 +139,22 @@ func TestServerConfigureProvider(t *testing.T) { }, }, }, + "response-resourcedata": { + server: &fwserver.Server{ + Provider: &testprovider.Provider{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{}, nil + }, + ConfigureMethod: func(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { + resp.ResourceData = "test-provider-configure-value" + }, + }, + }, + request: &provider.ConfigureRequest{}, + expectedResponse: &provider.ConfigureResponse{ + ResourceData: "test-provider-configure-value", + }, + }, } for name, testCase := range testCases { @@ -137,6 +169,14 @@ func TestServerConfigureProvider(t *testing.T) { if diff := cmp.Diff(response, testCase.expectedResponse); diff != "" { t.Errorf("unexpected difference: %s", diff) } + + if diff := cmp.Diff(testCase.server.DataSourceConfigureData, testCase.expectedResponse.DataSourceData); diff != "" { + t.Errorf("unexpected server.DataSourceConfigureData difference: %s", diff) + } + + if diff := cmp.Diff(testCase.server.ResourceConfigureData, testCase.expectedResponse.ResourceData); diff != "" { + t.Errorf("unexpected server.ResourceConfigureData difference: %s", diff) + } }) } } diff --git a/internal/fwserver/server_createresource.go b/internal/fwserver/server_createresource.go index 30838e1bb..bb5271341 100644 --- a/internal/fwserver/server_createresource.go +++ b/internal/fwserver/server_createresource.go @@ -9,7 +9,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/tfsdk" ) @@ -22,7 +21,7 @@ type CreateResourceRequest struct { PlannedState *tfsdk.Plan ProviderMeta *tfsdk.Config ResourceSchema fwschema.Schema - ResourceType provider.ResourceType + Resource resource.Resource } // CreateResourceResponse is the framework server response for a create request @@ -40,15 +39,23 @@ func (s *Server) CreateResource(ctx context.Context, req *CreateResourceRequest, return } - // Always instantiate new Resource instances. - logging.FrameworkDebug(ctx, "Calling provider defined ResourceType NewResource") - resourceImpl, diags := req.ResourceType.NewResource(ctx, s.Provider) - logging.FrameworkDebug(ctx, "Called provider defined ResourceType NewResource") + if _, ok := req.Resource.(resource.ResourceWithConfigure); ok { + logging.FrameworkTrace(ctx, "Resource implements ResourceWithConfigure") - resp.Diagnostics.Append(diags...) + configureReq := resource.ConfigureRequest{ + ProviderData: s.ResourceConfigureData, + } + configureResp := resource.ConfigureResponse{} - if resp.Diagnostics.HasError() { - return + logging.FrameworkDebug(ctx, "Calling provider defined Resource Configure") + req.Resource.(resource.ResourceWithConfigure).Configure(ctx, configureReq, &configureResp) + logging.FrameworkDebug(ctx, "Called provider defined Resource Configure") + + resp.Diagnostics.Append(configureResp.Diagnostics...) + + if resp.Diagnostics.HasError() { + return + } } nullSchemaData := tftypes.NewValue(req.ResourceSchema.Type().TerraformType(ctx), nil) @@ -87,7 +94,7 @@ func (s *Server) CreateResource(ctx context.Context, req *CreateResourceRequest, } logging.FrameworkDebug(ctx, "Calling provider defined Resource Create") - resourceImpl.Create(ctx, createReq, &createResp) + req.Resource.Create(ctx, createReq, &createResp) logging.FrameworkDebug(ctx, "Called provider defined Resource Create") resp.Diagnostics = createResp.Diagnostics @@ -99,7 +106,7 @@ func (s *Server) CreateResource(ctx context.Context, req *CreateResourceRequest, "The resource may have been successfully created, but Terraform is not tracking it. " + "Applying the configuration again with no other action may result in duplicate resource errors." - if _, ok := resourceImpl.(resource.ResourceWithImportState); ok { + if _, ok := req.Resource.(resource.ResourceWithImportState); ok { detail += " Import the resource if the resource was actually created and Terraform should be tracking it." } diff --git a/internal/fwserver/server_createresource_test.go b/internal/fwserver/server_createresource_test.go index 70e1f2c19..c74087572 100644 --- a/internal/fwserver/server_createresource_test.go +++ b/internal/fwserver/server_createresource_test.go @@ -2,6 +2,7 @@ package fwserver_test import ( "context" + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -11,7 +12,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" - "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" @@ -108,25 +108,18 @@ func TestServerCreateResource(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - var data testSchemaData + Resource: &testprovider.Resource{ + CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - if data.TestRequired.Value != "test-config-value" { - resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) - } + if data.TestRequired.Value != "test-config-value" { + resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) + } - // Prevent missing resource state error diagnostic - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) - }, - }, nil + // Prevent missing resource state error diagnostic + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) }, }, }, @@ -154,25 +147,18 @@ func TestServerCreateResource(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - var data testSchemaData + Resource: &testprovider.Resource{ + CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - if data.TestRequired.Value != "test-plannedstate-value" { - resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestRequired.Value) - } + if data.TestRequired.Value != "test-plannedstate-value" { + resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestRequired.Value) + } - // Prevent missing resource state error diagnostic - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) - }, - }, nil + // Prevent missing resource state error diagnostic + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) }, }, }, @@ -200,28 +186,21 @@ func TestServerCreateResource(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - var metadata testProviderMetaData + Resource: &testprovider.Resource{ + CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var metadata testProviderMetaData - resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &metadata)...) + resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &metadata)...) - if metadata.TestProviderMetaAttribute.Value != "test-provider-meta-value" { - resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+metadata.TestProviderMetaAttribute.Value) - } + if metadata.TestProviderMetaAttribute.Value != "test-provider-meta-value" { + resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+metadata.TestProviderMetaAttribute.Value) + } - // Prevent missing resource state error diagnostic - var data testSchemaData + // Prevent missing resource state error diagnostic + var data testSchemaData - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) - }, - }, nil + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) }, }, ProviderMeta: testProviderMetaConfig, @@ -237,23 +216,76 @@ func TestServerCreateResource(t *testing.T) { Private: testEmptyPrivate, }, }, + "resource-configure-data": { + server: &fwserver.Server{ + Provider: &testprovider.Provider{}, + ResourceConfigureData: "test-provider-configure-value", + }, + request: &fwserver.CreateResourceRequest{ + PlannedState: &tfsdk.Plan{ + Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{ + "test_computed": tftypes.NewValue(tftypes.String, nil), + "test_required": tftypes.NewValue(tftypes.String, "test-plannedstate-value"), + }), + Schema: testSchema, + }, + ResourceSchema: testSchema, + Resource: &testprovider.ResourceWithConfigure{ + ConfigureMethod: func(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + providerData, ok := req.ProviderData.(string) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected ConfigureRequest.ProviderData", + fmt.Sprintf("Expected string, got: %T", req.ProviderData), + ) + return + } + + if providerData != "test-provider-configure-value" { + resp.Diagnostics.AddError( + "Unexpected ConfigureRequest.ProviderData", + fmt.Sprintf("Expected test-provider-configure-value, got: %q", providerData), + ) + } + }, + Resource: &testprovider.Resource{ + CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + // In practice, the Configure method would save the + // provider data to the Resource implementation and + // use it here. The fact that Configure is able to + // read the data proves this can work. + + // Prevent missing resource state error diagnostic + var data testSchemaData + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + }, + }, + }, + }, + expectedResponse: &fwserver.CreateResourceResponse{ + NewState: &tfsdk.State{ + Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{ + "test_computed": tftypes.NewValue(tftypes.String, nil), + "test_required": tftypes.NewValue(tftypes.String, "test-plannedstate-value"), + }), + Schema: testSchema, + }, + Private: testEmptyPrivate, + }, + }, "response-diagnostics": { server: &fwserver.Server{ Provider: &testprovider.Provider{}, }, request: &fwserver.CreateResourceRequest{ ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil + Resource: &testprovider.Resource{ + CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") }, }, }, @@ -286,19 +318,12 @@ func TestServerCreateResource(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - var data testSchemaData - - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) - }, - }, nil + Resource: &testprovider.Resource{ + CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data testSchemaData + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) }, }, }, @@ -326,16 +351,9 @@ func TestServerCreateResource(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - // Intentionally missing resp.State.Set() - }, - }, nil + Resource: &testprovider.Resource{ + CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + // Intentionally missing resp.State.Set() }, }, }, @@ -359,23 +377,16 @@ func TestServerCreateResource(t *testing.T) { }, request: &fwserver.CreateResourceRequest{ ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - var data testSchemaData + Resource: &testprovider.Resource{ + CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data testSchemaData - // Prevent missing resource state error diagnostic - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + // Prevent missing resource state error diagnostic + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) - diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) + diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) - resp.Diagnostics.Append(diags...) - }, - }, nil + resp.Diagnostics.Append(diags...) }, }, }, diff --git a/internal/fwserver/server_deleteresource.go b/internal/fwserver/server_deleteresource.go index cb2768275..c7e48bce9 100644 --- a/internal/fwserver/server_deleteresource.go +++ b/internal/fwserver/server_deleteresource.go @@ -9,7 +9,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/tfsdk" ) @@ -21,7 +20,7 @@ type DeleteResourceRequest struct { PriorState *tfsdk.State ProviderMeta *tfsdk.Config ResourceSchema fwschema.Schema - ResourceType provider.ResourceType + Resource resource.Resource } // DeleteResourceResponse is the framework server response for a delete request @@ -39,15 +38,23 @@ func (s *Server) DeleteResource(ctx context.Context, req *DeleteResourceRequest, return } - // Always instantiate new Resource instances. - logging.FrameworkDebug(ctx, "Calling provider defined ResourceType NewResource") - resourceImpl, diags := req.ResourceType.NewResource(ctx, s.Provider) - logging.FrameworkDebug(ctx, "Called provider defined ResourceType NewResource") + if _, ok := req.Resource.(resource.ResourceWithConfigure); ok { + logging.FrameworkTrace(ctx, "Resource implements ResourceWithConfigure") - resp.Diagnostics.Append(diags...) + configureReq := resource.ConfigureRequest{ + ProviderData: s.ResourceConfigureData, + } + configureResp := resource.ConfigureResponse{} - if resp.Diagnostics.HasError() { - return + logging.FrameworkDebug(ctx, "Calling provider defined Resource Configure") + req.Resource.(resource.ResourceWithConfigure).Configure(ctx, configureReq, &configureResp) + logging.FrameworkDebug(ctx, "Called provider defined Resource Configure") + + resp.Diagnostics.Append(configureResp.Diagnostics...) + + if resp.Diagnostics.HasError() { + return + } } deleteReq := resource.DeleteRequest{ @@ -77,7 +84,7 @@ func (s *Server) DeleteResource(ctx context.Context, req *DeleteResourceRequest, } logging.FrameworkDebug(ctx, "Calling provider defined Resource Delete") - resourceImpl.Delete(ctx, deleteReq, &deleteResp) + req.Resource.Delete(ctx, deleteReq, &deleteResp) logging.FrameworkDebug(ctx, "Called provider defined Resource Delete") if !deleteResp.Diagnostics.HasError() { diff --git a/internal/fwserver/server_deleteresource_test.go b/internal/fwserver/server_deleteresource_test.go index b97a82567..9bf57ff95 100644 --- a/internal/fwserver/server_deleteresource_test.go +++ b/internal/fwserver/server_deleteresource_test.go @@ -13,7 +13,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" - "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" @@ -104,22 +103,15 @@ func TestServerDeleteResource(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - var data testSchemaData + Resource: &testprovider.Resource{ + DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) - if data.TestRequired.Value != "test-priorstate-value" { - resp.Diagnostics.AddError("unexpected req.State value: %s", data.TestRequired.Value) - } - }, - }, nil + if data.TestRequired.Value != "test-priorstate-value" { + resp.Diagnostics.AddError("unexpected req.State value: %s", data.TestRequired.Value) + } }, }, }, @@ -140,22 +132,15 @@ func TestServerDeleteResource(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - var data testProviderMetaData + Resource: &testprovider.Resource{ + DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data testProviderMetaData - resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) + resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) - if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { - resp.Diagnostics.AddError("unexpected req.ProviderMeta value: %s", data.TestProviderMetaAttribute.Value) - } - }, - }, nil + if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { + resp.Diagnostics.AddError("unexpected req.ProviderMeta value: %s", data.TestProviderMetaAttribute.Value) + } }, }, ProviderMeta: testProviderMetaConfig, @@ -170,26 +155,19 @@ func TestServerDeleteResource(t *testing.T) { }, request: &fwserver.DeleteResourceRequest{ ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` - got, diags := req.Private.GetKey(ctx, "providerKeyOne") + Resource: &testprovider.Resource{ + DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` + got, diags := req.Private.GetKey(ctx, "providerKeyOne") - resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(diags...) - if string(got) != expected { - resp.Diagnostics.AddError( - "Unexpected req.Private Value", - fmt.Sprintf("expected %q, got %q", expected, got), - ) - } - }, - }, nil + if string(got) != expected { + resp.Diagnostics.AddError( + "Unexpected req.Private Value", + fmt.Sprintf("expected %q, got %q", expected, got), + ) + } }, }, PlannedPrivate: &privatestate.Data{ @@ -206,27 +184,20 @@ func TestServerDeleteResource(t *testing.T) { }, request: &fwserver.DeleteResourceRequest{ ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - var expected []byte + Resource: &testprovider.Resource{ + DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var expected []byte - got, diags := req.Private.GetKey(ctx, "providerKeyOne") + got, diags := req.Private.GetKey(ctx, "providerKeyOne") - resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(diags...) - if !bytes.Equal(got, expected) { - resp.Diagnostics.AddError( - "Unexpected req.Private Value", - fmt.Sprintf("expected %q, got %q", expected, got), - ) - } - }, - }, nil + if !bytes.Equal(got, expected) { + resp.Diagnostics.AddError( + "Unexpected req.Private Value", + fmt.Sprintf("expected %q, got %q", expected, got), + ) + } }, }, }, @@ -247,17 +218,10 @@ func TestServerDeleteResource(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil + Resource: &testprovider.Resource{ + DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") }, }, }, @@ -281,6 +245,46 @@ func TestServerDeleteResource(t *testing.T) { }, }, }, + "resource-configure-data": { + server: &fwserver.Server{ + Provider: &testprovider.Provider{}, + ResourceConfigureData: "test-provider-configure-value", + }, + request: &fwserver.DeleteResourceRequest{ + ResourceSchema: testSchema, + Resource: &testprovider.ResourceWithConfigure{ + ConfigureMethod: func(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + providerData, ok := req.ProviderData.(string) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected ConfigureRequest.ProviderData", + fmt.Sprintf("Expected string, got: %T", req.ProviderData), + ) + return + } + + if providerData != "test-provider-configure-value" { + resp.Diagnostics.AddError( + "Unexpected ConfigureRequest.ProviderData", + fmt.Sprintf("Expected test-provider-configure-value, got: %q", providerData), + ) + } + }, + Resource: &testprovider.Resource{ + DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + // In practice, the Configure method would save the + // provider data to the Resource implementation and + // use it here. The fact that Configure is able to + // read the data proves this can work. + }, + }, + }, + }, + expectedResponse: &fwserver.DeleteResourceResponse{ + NewState: testEmptyState, + }, + }, "response-newstate": { server: &fwserver.Server{ Provider: &testprovider.Provider{}, @@ -294,16 +298,9 @@ func TestServerDeleteResource(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - // Intentionally empty, should call resp.State.RemoveResource() automatically. - }, - }, nil + Resource: &testprovider.Resource{ + DeleteMethod: func(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + // Intentionally empty, should call resp.State.RemoveResource() automatically. }, }, }, diff --git a/internal/fwserver/server_getproviderschema.go b/internal/fwserver/server_getproviderschema.go index 54e9460ff..2e7f8cab2 100644 --- a/internal/fwserver/server_getproviderschema.go +++ b/internal/fwserver/server_getproviderschema.go @@ -5,6 +5,8 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" + "github.com/hashicorp/terraform-plugin-framework/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/provider" ) // GetProviderSchemaRequest is the framework server request for the @@ -28,6 +30,19 @@ 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{} + + 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 + } + providerSchema, diags := s.ProviderSchema(ctx) resp.Diagnostics.Append(diags...) diff --git a/internal/fwserver/server_getproviderschema_test.go b/internal/fwserver/server_getproviderschema_test.go index a867c5a84..89b89a14e 100644 --- a/internal/fwserver/server_getproviderschema_test.go +++ b/internal/fwserver/server_getproviderschema_test.go @@ -5,11 +5,13 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" "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" ) @@ -35,9 +37,297 @@ func TestServerGetProviderSchema(t *testing.T) { }, }, }, - "datasourceschemas": { + "datasourceschemas-DataSources": { server: &fwserver.Server{ Provider: &testprovider.Provider{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source1" + }, + } + }, + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test2": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source2" + }, + } + }, + } + }, + }, + }, + request: &fwserver.GetProviderSchemaRequest{}, + expectedResponse: &fwserver.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source1": tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, + "test_data_source2": tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test2": { + Required: true, + Type: types.StringType, + }, + }, + }, + }, + Provider: &tfsdk.Schema{}, + ResourceSchemas: map[string]fwschema.Schema{}, + ServerCapabilities: &fwserver.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "datasourceschemas-DataSources-duplicate-type-name": { + server: &fwserver.Server{ + Provider: &testprovider.Provider{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + } + }, + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test2": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + } + }, + } + }, + }, + }, + request: &fwserver.GetProviderSchemaRequest{}, + expectedResponse: &fwserver.GetProviderSchemaResponse{ + DataSourceSchemas: nil, + Diagnostics: diag.Diagnostics{ + diag.NewErrorDiagnostic( + "Duplicate Data Source Type Defined", + "The test_data_source data source type name was returned for multiple data sources. "+ + "Data source type names must be unique. "+ + "This is always an issue with the provider and should be reported to the provider developers.", + ), + }, + Provider: &tfsdk.Schema{}, + ResourceSchemas: map[string]fwschema.Schema{}, + ServerCapabilities: &fwserver.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "datasourceschemas-DataSources-empty-type-name": { + server: &fwserver.Server{ + Provider: &testprovider.Provider{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithMetadata{ + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "" + }, + } + }, + } + }, + }, + }, + request: &fwserver.GetProviderSchemaRequest{}, + expectedResponse: &fwserver.GetProviderSchemaResponse{ + DataSourceSchemas: nil, + Diagnostics: diag.Diagnostics{ + diag.NewErrorDiagnostic( + "Data Source Type Name Missing", + "The *testprovider.DataSourceWithMetadata DataSource returned an empty string from the Metadata method. "+ + "This is always an issue with the provider and should be reported to the provider developers.", + ), + }, + Provider: &tfsdk.Schema{}, + ResourceSchemas: map[string]fwschema.Schema{}, + ServerCapabilities: &fwserver.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "datasourceschemas-DataSources-missing-schema": { + server: &fwserver.Server{ + Provider: &testprovider.Provider{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithMetadata{ + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + } + }, + } + }, + }, + }, + request: &fwserver.GetProviderSchemaRequest{}, + expectedResponse: &fwserver.GetProviderSchemaResponse{ + DataSourceSchemas: nil, + Diagnostics: diag.Diagnostics{ + diag.NewErrorDiagnostic( + "Data Source Schema Missing", + "The *testprovider.DataSourceWithMetadata DataSource in the provider is missing the GetSchema method. "+ + "This is always an issue with the provider and should be reported to the provider developers.", + ), + }, + Provider: &tfsdk.Schema{}, + ResourceSchemas: map[string]fwschema.Schema{}, + ServerCapabilities: &fwserver.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "datasourceschemas-DataSources-missing-type-name": { + server: &fwserver.Server{ + Provider: &testprovider.Provider{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchema{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + } + }, + } + }, + }, + }, + request: &fwserver.GetProviderSchemaRequest{}, + expectedResponse: &fwserver.GetProviderSchemaResponse{ + DataSourceSchemas: nil, + Diagnostics: diag.Diagnostics{ + diag.NewErrorDiagnostic( + "Data Source Type Name Missing", + "The *testprovider.DataSourceWithGetSchema DataSource in the provider DataSources method results is missing the Metadata method. "+ + "This is always an issue with the provider and should be reported to the provider developers.", + ), + }, + Provider: &tfsdk.Schema{}, + ResourceSchemas: map[string]fwschema.Schema{}, + ServerCapabilities: &fwserver.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "datasourceschemas-DataSources-provider-type-name": { + server: &fwserver.Server{ + Provider: &testprovider.ProviderWithMetadata{ + 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.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_data_source" + }, + } + }, + } + }, + }, + }, + }, + request: &fwserver.GetProviderSchemaRequest{}, + expectedResponse: &fwserver.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]fwschema.Schema{ + "testprovidertype_data_source": tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test": { + Required: true, + Type: types.StringType, + }, + }, + }, + }, + Provider: &tfsdk.Schema{}, + ResourceSchemas: map[string]fwschema.Schema{}, + ServerCapabilities: &fwserver.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "datasourceschemas-GetDataSources": { + server: &fwserver.Server{ + Provider: &testprovider.ProviderWithGetDataSources{ + //nolint:staticcheck // Internal implementation GetDataSourcesMethod: func(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { return map[string]provider.DataSourceType{ "test_data_source1": &testprovider.DataSourceType{ @@ -161,9 +451,10 @@ func TestServerGetProviderSchema(t *testing.T) { }, }, }, - "resourceschemas": { + "resourceschemas-GetResources": { server: &fwserver.Server{ - Provider: &testprovider.Provider{ + Provider: &testprovider.ProviderWithGetResources{ + //nolint:staticcheck // Internal implementation GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { return map[string]provider.ResourceType{ "test_resource1": &testprovider.ResourceType{ @@ -221,6 +512,293 @@ func TestServerGetProviderSchema(t *testing.T) { }, }, }, + "resourceschemas-Resources": { + server: &fwserver.Server{ + Provider: &testprovider.Provider{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource1" + }, + } + }, + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test2": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource2" + }, + } + }, + } + }, + }, + }, + request: &fwserver.GetProviderSchemaRequest{}, + expectedResponse: &fwserver.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]fwschema.Schema{}, + Provider: &tfsdk.Schema{}, + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource1": tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, + "test_resource2": tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test2": { + Required: true, + Type: types.StringType, + }, + }, + }, + }, + ServerCapabilities: &fwserver.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "resourceschemas-Resources-duplicate-type-name": { + server: &fwserver.Server{ + Provider: &testprovider.Provider{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + } + }, + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test2": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + } + }, + } + }, + }, + }, + request: &fwserver.GetProviderSchemaRequest{}, + expectedResponse: &fwserver.GetProviderSchemaResponse{ + DataSourceSchemas: nil, + Diagnostics: diag.Diagnostics{ + diag.NewErrorDiagnostic( + "Duplicate Resource Type Defined", + "The test_resource resource type name was returned for multiple resources. "+ + "Resource type names must be unique. "+ + "This is always an issue with the provider and should be reported to the provider developers.", + ), + }, + Provider: &tfsdk.Schema{}, + ResourceSchemas: nil, + ServerCapabilities: &fwserver.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "resourceschemas-Resources-empty-type-name": { + server: &fwserver.Server{ + Provider: &testprovider.Provider{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithMetadata{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "" + }, + } + }, + } + }, + }, + }, + request: &fwserver.GetProviderSchemaRequest{}, + expectedResponse: &fwserver.GetProviderSchemaResponse{ + DataSourceSchemas: nil, + Diagnostics: diag.Diagnostics{ + diag.NewErrorDiagnostic( + "Resource Type Name Missing", + "The *testprovider.ResourceWithMetadata Resource returned an empty string from the Metadata method. "+ + "This is always an issue with the provider and should be reported to the provider developers.", + ), + }, + Provider: &tfsdk.Schema{}, + ResourceSchemas: nil, + ServerCapabilities: &fwserver.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "resourceschemas-Resources-missing-schema": { + server: &fwserver.Server{ + Provider: &testprovider.Provider{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithMetadata{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + } + }, + } + }, + }, + }, + request: &fwserver.GetProviderSchemaRequest{}, + expectedResponse: &fwserver.GetProviderSchemaResponse{ + DataSourceSchemas: nil, + Diagnostics: diag.Diagnostics{ + diag.NewErrorDiagnostic( + "Resource Schema Missing", + "The *testprovider.ResourceWithMetadata Resource in the provider is missing the GetSchema method. "+ + "This is always an issue with the provider and should be reported to the provider developers.", + ), + }, + Provider: &tfsdk.Schema{}, + ResourceSchemas: nil, + ServerCapabilities: &fwserver.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "resourceschemas-Resources-missing-type-name": { + server: &fwserver.Server{ + Provider: &testprovider.Provider{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchema{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + } + }, + } + }, + }, + }, + request: &fwserver.GetProviderSchemaRequest{}, + expectedResponse: &fwserver.GetProviderSchemaResponse{ + DataSourceSchemas: nil, + Diagnostics: diag.Diagnostics{ + diag.NewErrorDiagnostic( + "Resource Type Name Missing", + "The *testprovider.ResourceWithGetSchema Resource in the provider Resources method results is missing the Metadata method. "+ + "This is always an issue with the provider and should be reported to the provider developers.", + ), + }, + Provider: &tfsdk.Schema{}, + ResourceSchemas: nil, + ServerCapabilities: &fwserver.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "resourceschemas-Resources-provider-type-name": { + server: &fwserver.Server{ + Provider: &testprovider.ProviderWithMetadata{ + 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.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_resource" + }, + } + }, + } + }, + }, + }, + }, + request: &fwserver.GetProviderSchemaRequest{}, + expectedResponse: &fwserver.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]fwschema.Schema{}, + Provider: &tfsdk.Schema{}, + ResourceSchemas: map[string]fwschema.Schema{ + "testprovidertype_resource": tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test": { + Required: true, + Type: types.StringType, + }, + }, + }, + }, + ServerCapabilities: &fwserver.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, } for name, testCase := range testCases { diff --git a/internal/fwserver/server_importresourcestate.go b/internal/fwserver/server_importresourcestate.go index fd8ae410e..0c70c7a3a 100644 --- a/internal/fwserver/server_importresourcestate.go +++ b/internal/fwserver/server_importresourcestate.go @@ -6,7 +6,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/tfsdk" ) @@ -21,8 +20,8 @@ type ImportedResource struct { // ImportResourceStateRequest is the framework server request for the // ImportResourceState RPC. type ImportResourceStateRequest struct { - ID string - ResourceType provider.ResourceType + ID string + Resource resource.Resource // EmptyState is an empty State for the resource schema. This is used to // initialize the ImportedResource State of the ImportResourceStateResponse @@ -48,18 +47,26 @@ func (s *Server) ImportResourceState(ctx context.Context, req *ImportResourceSta return } - // Always instantiate new Resource instances. - logging.FrameworkDebug(ctx, "Calling provider defined ResourceType NewResource") - resourceImpl, diags := req.ResourceType.NewResource(ctx, s.Provider) - logging.FrameworkDebug(ctx, "Called provider defined ResourceType NewResource") + if _, ok := req.Resource.(resource.ResourceWithConfigure); ok { + logging.FrameworkTrace(ctx, "Resource implements ResourceWithConfigure") - resp.Diagnostics.Append(diags...) + configureReq := resource.ConfigureRequest{ + ProviderData: s.ResourceConfigureData, + } + configureResp := resource.ConfigureResponse{} - if resp.Diagnostics.HasError() { - return + logging.FrameworkDebug(ctx, "Calling provider defined Resource Configure") + req.Resource.(resource.ResourceWithConfigure).Configure(ctx, configureReq, &configureResp) + logging.FrameworkDebug(ctx, "Called provider defined Resource Configure") + + resp.Diagnostics.Append(configureResp.Diagnostics...) + + if resp.Diagnostics.HasError() { + return + } } - resourceWithImportState, ok := resourceImpl.(resource.ResourceWithImportState) + resourceWithImportState, ok := req.Resource.(resource.ResourceWithImportState) if !ok { // If there is a feature request for customizing this messaging, diff --git a/internal/fwserver/server_importresourcestate_test.go b/internal/fwserver/server_importresourcestate_test.go index 5cd09d97a..653dce1be 100644 --- a/internal/fwserver/server_importresourcestate_test.go +++ b/internal/fwserver/server_importresourcestate_test.go @@ -2,6 +2,7 @@ package fwserver_test import ( "context" + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -12,7 +13,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" "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" @@ -102,21 +102,14 @@ func TestServerImportResourceState(t *testing.T) { request: &fwserver.ImportResourceStateRequest{ EmptyState: *testEmptyState, ID: "test-id", - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithImportState{ - Resource: &testprovider.Resource{}, - ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { - if req.ID != "test-id" { - resp.Diagnostics.AddError("unexpected req.ID value: %s", req.ID) - } + Resource: &testprovider.ResourceWithImportState{ + Resource: &testprovider.Resource{}, + ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + if req.ID != "test-id" { + resp.Diagnostics.AddError("unexpected req.ID value: %s", req.ID) + } - resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) - }, - }, nil + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) }, }, TypeName: "test_resource", @@ -138,15 +131,8 @@ func TestServerImportResourceState(t *testing.T) { request: &fwserver.ImportResourceStateRequest{ EmptyState: *testEmptyState, ID: "test-id", - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, - }, - TypeName: "test_resource", + Resource: &testprovider.Resource{}, + TypeName: "test_resource", }, expectedResponse: &fwserver.ImportResourceStateResponse{ Diagnostics: diag.Diagnostics{ @@ -157,6 +143,55 @@ func TestServerImportResourceState(t *testing.T) { }, }, }, + "resource-configure-data": { + server: &fwserver.Server{ + Provider: &testprovider.Provider{}, + ResourceConfigureData: "test-provider-configure-value", + }, + request: &fwserver.ImportResourceStateRequest{ + EmptyState: *testEmptyState, + ID: "test-id", + TypeName: "test_resource", + Resource: &testprovider.ResourceWithConfigureAndImportState{ + ConfigureMethod: func(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + providerData, ok := req.ProviderData.(string) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected ConfigureRequest.ProviderData", + fmt.Sprintf("Expected string, got: %T", req.ProviderData), + ) + return + } + + if providerData != "test-provider-configure-value" { + resp.Diagnostics.AddError( + "Unexpected ConfigureRequest.ProviderData", + fmt.Sprintf("Expected test-provider-configure-value, got: %q", providerData), + ) + } + }, + ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + // In practice, the Configure method would save the + // provider data to the Resource implementation and + // use it here. The fact that Configure is able to + // read the data proves this can work. + + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) + }, + Resource: &testprovider.Resource{}, + }, + }, + expectedResponse: &fwserver.ImportResourceStateResponse{ + ImportedResources: []fwserver.ImportedResource{ + { + State: *testState, + TypeName: "test_resource", + Private: testEmptyPrivate, + }, + }, + }, + }, "response-diagnostics": { server: &fwserver.Server{ Provider: &testprovider.Provider{}, @@ -164,18 +199,11 @@ func TestServerImportResourceState(t *testing.T) { request: &fwserver.ImportResourceStateRequest{ EmptyState: *testEmptyState, ID: "test-id", - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithImportState{ - Resource: &testprovider.Resource{}, - ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil + Resource: &testprovider.ResourceWithImportState{ + Resource: &testprovider.Resource{}, + ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") }, }, }, @@ -199,17 +227,10 @@ func TestServerImportResourceState(t *testing.T) { request: &fwserver.ImportResourceStateRequest{ EmptyState: *testEmptyState, ID: "test-id", - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithImportState{ - Resource: &testprovider.Resource{}, - ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { - resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) - }, - }, nil + Resource: &testprovider.ResourceWithImportState{ + Resource: &testprovider.Resource{}, + ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) }, }, TypeName: "test_resource", @@ -231,21 +252,14 @@ func TestServerImportResourceState(t *testing.T) { request: &fwserver.ImportResourceStateRequest{ EmptyState: *testEmptyState, ID: "test-id", - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithImportState{ - Resource: &testprovider.Resource{}, - ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { - diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) + Resource: &testprovider.ResourceWithImportState{ + Resource: &testprovider.Resource{}, + ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) - resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(diags...) - resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) - }, - }, nil + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) }, }, TypeName: "test_resource", @@ -267,17 +281,10 @@ func TestServerImportResourceState(t *testing.T) { request: &fwserver.ImportResourceStateRequest{ EmptyState: *testEmptyState, ID: "test-id", - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithImportState{ - Resource: &testprovider.Resource{}, - ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { - // Intentionally empty - }, - }, nil + Resource: &testprovider.ResourceWithImportState{ + Resource: &testprovider.Resource{}, + ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + // Intentionally empty }, }, TypeName: "test_resource", diff --git a/internal/fwserver/server_planresourcechange.go b/internal/fwserver/server_planresourcechange.go index 1ee43276f..e81927195 100644 --- a/internal/fwserver/server_planresourcechange.go +++ b/internal/fwserver/server_planresourcechange.go @@ -13,7 +13,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" "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" ) @@ -27,7 +26,7 @@ type PlanResourceChangeRequest struct { ProposedNewState *tfsdk.Plan ProviderMeta *tfsdk.Config ResourceSchema fwschema.Schema - ResourceType provider.ResourceType + Resource resource.Resource } // PlanResourceChangeResponse is the framework server response for the @@ -45,15 +44,23 @@ func (s *Server) PlanResourceChange(ctx context.Context, req *PlanResourceChange return } - // Always instantiate new Resource instances. - logging.FrameworkDebug(ctx, "Calling provider defined ResourceType NewResource") - resourceImpl, diags := req.ResourceType.NewResource(ctx, s.Provider) - logging.FrameworkDebug(ctx, "Called provider defined ResourceType NewResource") + if _, ok := req.Resource.(resource.ResourceWithConfigure); ok { + logging.FrameworkTrace(ctx, "Resource implements ResourceWithConfigure") - resp.Diagnostics.Append(diags...) + configureReq := resource.ConfigureRequest{ + ProviderData: s.ResourceConfigureData, + } + configureResp := resource.ConfigureResponse{} - if resp.Diagnostics.HasError() { - return + logging.FrameworkDebug(ctx, "Calling provider defined Resource Configure") + req.Resource.(resource.ResourceWithConfigure).Configure(ctx, configureReq, &configureResp) + logging.FrameworkDebug(ctx, "Called provider defined Resource Configure") + + resp.Diagnostics.Append(configureResp.Diagnostics...) + + if resp.Diagnostics.HasError() { + return + } } nullTfValue := tftypes.NewValue(req.ResourceSchema.Type().TerraformType(ctx), nil) @@ -211,7 +218,7 @@ func (s *Server) PlanResourceChange(ctx context.Context, req *PlanResourceChange // delete resources, e.g. to inform practitioners that the resource // _can't_ be deleted in the API and will just be removed from // Terraform's state - if resourceWithModifyPlan, ok := resourceImpl.(resource.ResourceWithModifyPlan); ok { + if resourceWithModifyPlan, ok := req.Resource.(resource.ResourceWithModifyPlan); ok { logging.FrameworkTrace(ctx, "Resource implements ResourceWithModifyPlan") modifyPlanReq := resource.ModifyPlanRequest{ diff --git a/internal/fwserver/server_planresourcechange_test.go b/internal/fwserver/server_planresourcechange_test.go index 33fc0aefc..3d0db6fda 100644 --- a/internal/fwserver/server_planresourcechange_test.go +++ b/internal/fwserver/server_planresourcechange_test.go @@ -2,6 +2,7 @@ package fwserver_test import ( "context" + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -14,7 +15,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" "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" @@ -473,6 +473,67 @@ func TestServerPlanResourceChange(t *testing.T) { request *fwserver.PlanResourceChangeRequest expectedResponse *fwserver.PlanResourceChangeResponse }{ + "resource-configure-data": { + server: &fwserver.Server{ + Provider: &testprovider.Provider{}, + ResourceConfigureData: "test-provider-configure-value", + }, + request: &fwserver.PlanResourceChangeRequest{ + Config: &tfsdk.Config{ + Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{ + "test_computed": tftypes.NewValue(tftypes.String, nil), + "test_required": tftypes.NewValue(tftypes.String, "test-config-value"), + }), + Schema: testSchema, + }, + ProposedNewState: &tfsdk.Plan{ + Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{ + "test_computed": tftypes.NewValue(tftypes.String, nil), + "test_required": tftypes.NewValue(tftypes.String, "test-config-value"), + }), + Schema: testSchema, + }, + PriorState: testEmptyState, + ResourceSchema: testSchema, + Resource: &testprovider.ResourceWithConfigureAndModifyPlan{ + ConfigureMethod: func(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + providerData, ok := req.ProviderData.(string) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected ConfigureRequest.ProviderData", + fmt.Sprintf("Expected string, got: %T", req.ProviderData), + ) + return + } + + if providerData != "test-provider-configure-value" { + resp.Diagnostics.AddError( + "Unexpected ConfigureRequest.ProviderData", + fmt.Sprintf("Expected test-provider-configure-value, got: %q", providerData), + ) + } + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + // In practice, the Configure method would save the + // provider data to the Resource implementation and + // use it here. The fact that Configure is able to + // read the data proves this can work. + }, + Resource: &testprovider.Resource{}, + }, + }, + expectedResponse: &fwserver.PlanResourceChangeResponse{ + PlannedState: &tfsdk.State{ + Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{ + "test_computed": tftypes.NewValue(tftypes.String, tftypes.UnknownValue), + "test_required": tftypes.NewValue(tftypes.String, "test-config-value"), + }), + Schema: testSchema, + }, + PlannedPrivate: testEmptyPrivate, + }, + }, "create-mark-computed-config-nils-as-unknown": { server: &fwserver.Server{ Provider: &testprovider.Provider{}, @@ -494,14 +555,7 @@ func TestServerPlanResourceChange(t *testing.T) { }, PriorState: testEmptyState, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, - }, + Resource: &testprovider.Resource{}, }, expectedResponse: &fwserver.PlanResourceChangeResponse{ PlannedState: &tfsdk.State{ @@ -535,15 +589,8 @@ func TestServerPlanResourceChange(t *testing.T) { }, PriorState: testEmptyState, ResourceSchema: testSchemaAttributePlanModifierPrivatePlanRequest, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchemaAttributePlanModifierPrivatePlanRequest, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, - }, - PriorPrivate: testPrivate, + Resource: &testprovider.Resource{}, + PriorPrivate: testPrivate, }, expectedResponse: &fwserver.PlanResourceChangeResponse{ PlannedState: &tfsdk.State{ @@ -600,14 +647,7 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchemaAttributePlanModifierAttributePlan, }, ResourceSchema: testSchemaAttributePlanModifierAttributePlan, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchemaAttributePlanModifierAttributePlan, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, - }, + Resource: &testprovider.Resource{}, }, expectedResponse: &fwserver.PlanResourceChangeResponse{ PlannedState: &tfsdk.State{ @@ -648,14 +688,7 @@ func TestServerPlanResourceChange(t *testing.T) { }, PriorState: testEmptyState, ResourceSchema: testSchemaAttributePlanModifierPrivatePlanResponse, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchemaAttributePlanModifierPrivatePlanResponse, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, - }, + Resource: &testprovider.Resource{}, }, expectedResponse: &fwserver.PlanResourceChangeResponse{ PlannedState: &tfsdk.State{ @@ -689,14 +722,7 @@ func TestServerPlanResourceChange(t *testing.T) { }, PriorState: testEmptyState, ResourceSchema: testSchemaAttributePlanModifierDiagnosticsError, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchemaAttributePlanModifierDiagnosticsError, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, - }, + Resource: &testprovider.Resource{}, }, expectedResponse: &fwserver.PlanResourceChangeResponse{ Diagnostics: diag.Diagnostics{ @@ -736,14 +762,7 @@ func TestServerPlanResourceChange(t *testing.T) { }, PriorState: testEmptyState, ResourceSchema: testSchemaAttributePlanModifierRequiresReplace, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchemaAttributePlanModifierRequiresReplace, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, - }, + Resource: &testprovider.Resource{}, }, expectedResponse: &fwserver.PlanResourceChangeResponse{ PlannedState: &tfsdk.State{ @@ -785,22 +804,15 @@ func TestServerPlanResourceChange(t *testing.T) { }, PriorState: testEmptyState, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData - - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - - if data.TestRequired.Value != "test-config-value" { - resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) - } - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if data.TestRequired.Value != "test-config-value" { + resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) + } }, }, }, @@ -836,25 +848,18 @@ func TestServerPlanResourceChange(t *testing.T) { }, PriorState: testEmptyState, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` - key := "providerKeyOne" - got, diags := req.Private.GetKey(ctx, key) + key := "providerKeyOne" + got, diags := req.Private.GetKey(ctx, key) - resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(diags...) - if string(got) != expected { - resp.Diagnostics.AddError("unexpected req.Private.Provider value: %s", string(got)) - } - }, - }, nil + if string(got) != expected { + resp.Diagnostics.AddError("unexpected req.Private.Provider value: %s", string(got)) + } }, }, PriorPrivate: testPrivate, @@ -891,22 +896,15 @@ func TestServerPlanResourceChange(t *testing.T) { }, PriorState: testEmptyState, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData - - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - - if !data.TestComputed.Unknown { - resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestComputed.Value) - } - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if !data.TestComputed.Unknown { + resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestComputed.Value) + } }, }, }, @@ -943,22 +941,15 @@ func TestServerPlanResourceChange(t *testing.T) { PriorState: testEmptyState, ProviderMeta: testProviderMetaConfig, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testProviderMetaData - - resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) - - if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { - resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) - } - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testProviderMetaData + + resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) + + if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { + resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) + } }, }, }, @@ -994,17 +985,10 @@ func TestServerPlanResourceChange(t *testing.T) { }, PriorState: testEmptyState, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") }, }, }, @@ -1044,22 +1028,15 @@ func TestServerPlanResourceChange(t *testing.T) { }, PriorState: testEmptyState, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - data.TestComputed = types.String{Value: "test-plannedstate-value"} + data.TestComputed = types.String{Value: "test-plannedstate-value"} - resp.Diagnostics.Append(resp.Plan.Set(ctx, &data)...) - }, - }, nil + resp.Diagnostics.Append(resp.Plan.Set(ctx, &data)...) }, }, }, @@ -1095,18 +1072,11 @@ func TestServerPlanResourceChange(t *testing.T) { }, PriorState: testEmptyState, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) - - resp.Diagnostics.Append(diags...) - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) + + resp.Diagnostics.Append(diags...) }, }, }, @@ -1142,24 +1112,17 @@ func TestServerPlanResourceChange(t *testing.T) { }, PriorState: testEmptyState, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - // This is a strange thing to signal on creation, - // but the framework does not prevent you from - // doing it and it might be overly burdensome on - // provider developers to have the framework raise - // an error if it is technically valid in the - // protocol. - resp.RequiresReplace = path.Paths{ - path.Root("test_required"), - } - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + // This is a strange thing to signal on creation, + // but the framework does not prevent you from + // doing it and it might be overly burdensome on + // provider developers to have the framework raise + // an error if it is technically valid in the + // protocol. + resp.RequiresReplace = path.Paths{ + path.Root("test_required"), + } }, }, }, @@ -1196,25 +1159,18 @@ func TestServerPlanResourceChange(t *testing.T) { }, PriorState: testEmptyState, ResourceSchema: testSchemaAttributePlanModifierPrivatePlanResponse, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchemaAttributePlanModifierPrivatePlanResponse, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` - key := "providerKeyOne" - got, diags := req.Private.GetKey(ctx, key) + key := "providerKeyOne" + got, diags := req.Private.GetKey(ctx, key) - resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(diags...) - if string(got) != expected { - resp.Diagnostics.AddError("unexpected req.Private.Provider value: %s", string(got)) - } - }, - }, nil + if string(got) != expected { + resp.Diagnostics.AddError("unexpected req.Private.Provider value: %s", string(got)) + } }, }, }, @@ -1249,22 +1205,15 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData - - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - - if data.TestRequired.Value != "test-config-value" { - resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) - } - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if data.TestRequired.Value != "test-config-value" { + resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) + } }, }, }, @@ -1294,25 +1243,18 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` - key := "providerKeyOne" - got, diags := req.Private.GetKey(ctx, key) + key := "providerKeyOne" + got, diags := req.Private.GetKey(ctx, key) - resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(diags...) - if string(got) != expected { - resp.Diagnostics.AddError("unexpected req.Private.Provider value: %s", string(got)) - } - }, - }, nil + if string(got) != expected { + resp.Diagnostics.AddError("unexpected req.Private.Provider value: %s", string(got)) + } }, }, PriorPrivate: testPrivateProvider, @@ -1343,22 +1285,15 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData - - resp.Diagnostics.Append(req.State.Get(ctx, &data)...) - - if data.TestRequired.Value != "test-state-value" { - resp.Diagnostics.AddError("Unexpected req.State Value", "Got: "+data.TestRequired.Value) - } - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if data.TestRequired.Value != "test-state-value" { + resp.Diagnostics.AddError("Unexpected req.State Value", "Got: "+data.TestRequired.Value) + } }, }, }, @@ -1389,22 +1324,15 @@ func TestServerPlanResourceChange(t *testing.T) { }, ProviderMeta: testProviderMetaConfig, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testProviderMetaData - - resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) - - if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { - resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) - } - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testProviderMetaData + + resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) + + if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { + resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) + } }, }, }, @@ -1434,17 +1362,10 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") }, }, }, @@ -1478,17 +1399,10 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - // This is invalid logic to run during deletion. - resp.Diagnostics.Append(resp.Plan.SetAttribute(ctx, path.Root("test_computed"), types.String{Value: "test-plannedstate-value"})...) - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + // This is invalid logic to run during deletion. + resp.Diagnostics.Append(resp.Plan.SetAttribute(ctx, path.Root("test_computed"), types.String{Value: "test-plannedstate-value"})...) }, }, }, @@ -1532,24 +1446,17 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - // This is a strange thing to signal on creation, - // but the framework does not prevent you from - // doing it and it might be overly burdensome on - // provider developers to have the framework raise - // an error if it is technically valid in the - // protocol. - resp.RequiresReplace = path.Paths{ - path.Root("test_required"), - } - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + // This is a strange thing to signal on creation, + // but the framework does not prevent you from + // doing it and it might be overly burdensome on + // provider developers to have the framework raise + // an error if it is technically valid in the + // protocol. + resp.RequiresReplace = path.Paths{ + path.Root("test_required"), + } }, }, }, @@ -1582,18 +1489,11 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) - - resp.Diagnostics.Append(diags...) - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) + + resp.Diagnostics.Append(diags...) }, }, }, @@ -1621,18 +1521,11 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchemaAttributePlanModifierPrivatePlanResponse, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchemaAttributePlanModifierPrivatePlanResponse, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) - - resp.Diagnostics.Append(diags...) - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) + + resp.Diagnostics.Append(diags...) }, }, }, @@ -1668,14 +1561,7 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, - }, + Resource: &testprovider.Resource{}, }, expectedResponse: &fwserver.PlanResourceChangeResponse{ PlannedState: &tfsdk.State{ @@ -1715,15 +1601,8 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchemaAttributePlanModifierPrivatePlanRequest, }, ResourceSchema: testSchemaAttributePlanModifierPrivatePlanRequest, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchemaAttributePlanModifierPrivatePlanRequest, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, - }, - PriorPrivate: testPrivateProvider, + Resource: &testprovider.Resource{}, + PriorPrivate: testPrivateProvider, }, expectedResponse: &fwserver.PlanResourceChangeResponse{ PlannedState: &tfsdk.State{ @@ -1784,14 +1663,7 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchemaAttributePlanModifierAttributePlan, }, ResourceSchema: testSchemaAttributePlanModifierAttributePlan, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchemaAttributePlanModifierAttributePlan, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, - }, + Resource: &testprovider.Resource{}, }, expectedResponse: &fwserver.PlanResourceChangeResponse{ PlannedState: &tfsdk.State{ @@ -1859,14 +1731,7 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchemaAttributePlanModifierAttributePlan, }, ResourceSchema: testSchemaAttributePlanModifierAttributePlan, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchemaAttributePlanModifierAttributePlan, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, - }, + Resource: &testprovider.Resource{}, }, expectedResponse: &fwserver.PlanResourceChangeResponse{ PlannedState: &tfsdk.State{ @@ -1918,14 +1783,7 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchemaAttributePlanModifierPrivatePlanResponse, }, ResourceSchema: testSchemaAttributePlanModifierPrivatePlanResponse, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchemaAttributePlanModifierPrivatePlanResponse, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, - }, + Resource: &testprovider.Resource{}, }, expectedResponse: &fwserver.PlanResourceChangeResponse{ PlannedState: &tfsdk.State{ @@ -1965,14 +1823,7 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchemaAttributePlanModifierDiagnosticsError, }, ResourceSchema: testSchemaAttributePlanModifierDiagnosticsError, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchemaAttributePlanModifierDiagnosticsError, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, - }, + Resource: &testprovider.Resource{}, }, expectedResponse: &fwserver.PlanResourceChangeResponse{ Diagnostics: diag.Diagnostics{ @@ -2018,14 +1869,7 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchemaAttributePlanModifierRequiresReplace, }, ResourceSchema: testSchemaAttributePlanModifierRequiresReplace, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchemaAttributePlanModifierRequiresReplace, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, - }, + Resource: &testprovider.Resource{}, }, expectedResponse: &fwserver.PlanResourceChangeResponse{ PlannedState: &tfsdk.State{ @@ -2068,22 +1912,15 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData - - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - - if data.TestRequired.Value != "test-new-value" { - resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) - } - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if data.TestRequired.Value != "test-new-value" { + resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) + } }, }, }, @@ -2125,22 +1962,15 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData - - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - - if !data.TestComputed.Unknown { - resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestComputed.Value) - } - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if !data.TestComputed.Unknown { + resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestComputed.Value) + } }, }, }, @@ -2183,22 +2013,15 @@ func TestServerPlanResourceChange(t *testing.T) { }, ProviderMeta: testProviderMetaConfig, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testProviderMetaData - - resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) - - if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { - resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) - } - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testProviderMetaData + + resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) + + if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { + resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) + } }, }, }, @@ -2240,25 +2063,18 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` - key := "providerKeyOne" - got, diags := req.Private.GetKey(ctx, key) + key := "providerKeyOne" + got, diags := req.Private.GetKey(ctx, key) - resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(diags...) - if string(got) != expected { - resp.Diagnostics.AddError("unexpected req.Private.Provider value: %s", string(got)) - } - }, - }, nil + if string(got) != expected { + resp.Diagnostics.AddError("unexpected req.Private.Provider value: %s", string(got)) + } }, }, PriorPrivate: testPrivate, @@ -2301,17 +2117,10 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") }, }, }, @@ -2357,22 +2166,15 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - data.TestComputed = types.String{Value: "test-plannedstate-value"} + data.TestComputed = types.String{Value: "test-plannedstate-value"} - resp.Diagnostics.Append(resp.Plan.Set(ctx, &data)...) - }, - }, nil + resp.Diagnostics.Append(resp.Plan.Set(ctx, &data)...) }, }, }, @@ -2414,24 +2216,17 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - // This is a strange thing to signal on creation, - // but the framework does not prevent you from - // doing it and it might be overly burdensome on - // provider developers to have the framework raise - // an error if it is technically valid in the - // protocol. - resp.RequiresReplace = path.Paths{ - path.Root("test_required"), - } - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + // This is a strange thing to signal on creation, + // but the framework does not prevent you from + // doing it and it might be overly burdensome on + // provider developers to have the framework raise + // an error if it is technically valid in the + // protocol. + resp.RequiresReplace = path.Paths{ + path.Root("test_required"), + } }, }, }, @@ -2476,18 +2271,11 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) - - resp.Diagnostics.Append(diags...) - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) + + resp.Diagnostics.Append(diags...) }, }, }, @@ -2526,18 +2314,11 @@ func TestServerPlanResourceChange(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchemaAttributePlanModifierPrivatePlanResponse, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchemaAttributePlanModifierPrivatePlanResponse, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) - - resp.Diagnostics.Append(diags...) - }, - }, nil + Resource: &testprovider.ResourceWithModifyPlan{ + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) + + resp.Diagnostics.Append(diags...) }, }, }, diff --git a/internal/fwserver/server_readdatasource.go b/internal/fwserver/server_readdatasource.go index 1c116d7d1..c66fecdee 100644 --- a/internal/fwserver/server_readdatasource.go +++ b/internal/fwserver/server_readdatasource.go @@ -7,7 +7,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/logging" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/tfsdk" ) @@ -16,7 +15,7 @@ import ( type ReadDataSourceRequest struct { Config *tfsdk.Config DataSourceSchema fwschema.Schema - DataSourceType provider.DataSourceType + DataSource datasource.DataSource ProviderMeta *tfsdk.Config } @@ -33,15 +32,23 @@ func (s *Server) ReadDataSource(ctx context.Context, req *ReadDataSourceRequest, return } - // Always instantiate new DataSource instances. - logging.FrameworkDebug(ctx, "Calling provider defined DataSourceType NewDataSource") - dataSource, diags := req.DataSourceType.NewDataSource(ctx, s.Provider) - logging.FrameworkDebug(ctx, "Called provider defined DataSourceType NewDataSource") + if _, ok := req.DataSource.(datasource.DataSourceWithConfigure); ok { + logging.FrameworkTrace(ctx, "DataSource implements DataSourceWithConfigure") - resp.Diagnostics.Append(diags...) + configureReq := datasource.ConfigureRequest{ + ProviderData: s.DataSourceConfigureData, + } + configureResp := datasource.ConfigureResponse{} - if resp.Diagnostics.HasError() { - return + logging.FrameworkDebug(ctx, "Calling provider defined DataSource Configure") + req.DataSource.(datasource.DataSourceWithConfigure).Configure(ctx, configureReq, &configureResp) + logging.FrameworkDebug(ctx, "Called provider defined DataSource Configure") + + resp.Diagnostics.Append(configureResp.Diagnostics...) + + if resp.Diagnostics.HasError() { + return + } } readReq := datasource.ReadRequest{ @@ -65,7 +72,7 @@ func (s *Server) ReadDataSource(ctx context.Context, req *ReadDataSourceRequest, } logging.FrameworkDebug(ctx, "Calling provider defined DataSource Read") - dataSource.Read(ctx, readReq, &readResp) + req.DataSource.Read(ctx, readReq, &readResp) logging.FrameworkDebug(ctx, "Called provider defined DataSource Read") resp.Diagnostics = readResp.Diagnostics diff --git a/internal/fwserver/server_readdatasource_test.go b/internal/fwserver/server_readdatasource_test.go index 8358012ab..71db54bab 100644 --- a/internal/fwserver/server_readdatasource_test.go +++ b/internal/fwserver/server_readdatasource_test.go @@ -2,6 +2,7 @@ package fwserver_test import ( "context" + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -9,7 +10,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" - "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-go/tftypes" @@ -81,25 +81,18 @@ func TestServerReadDataSource(t *testing.T) { request: &fwserver.ReadDataSourceRequest{ Config: testConfig, DataSourceSchema: testSchema, - DataSourceType: &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSource{ - ReadMethod: func(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var config struct { - TestComputed types.String `tfsdk:"test_computed"` - TestRequired types.String `tfsdk:"test_required"` - } - - resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) - - if config.TestRequired.Value != "test-config-value" { - resp.Diagnostics.AddError("unexpected req.Config value: %s", config.TestRequired.Value) - } - }, - }, nil + DataSource: &testprovider.DataSource{ + ReadMethod: func(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var config struct { + TestComputed types.String `tfsdk:"test_computed"` + TestRequired types.String `tfsdk:"test_required"` + } + + resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) + + if config.TestRequired.Value != "test-config-value" { + resp.Diagnostics.AddError("unexpected req.Config value: %s", config.TestRequired.Value) + } }, }, }, @@ -114,25 +107,18 @@ func TestServerReadDataSource(t *testing.T) { request: &fwserver.ReadDataSourceRequest{ Config: testConfig, DataSourceSchema: testSchema, - DataSourceType: &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSource{ - ReadMethod: func(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var config struct { - TestComputed types.String `tfsdk:"test_computed"` - TestRequired types.String `tfsdk:"test_required"` - } - - resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &config)...) - - if config.TestRequired.Value != "test-config-value" { - resp.Diagnostics.AddError("unexpected req.ProviderMeta value: %s", config.TestRequired.Value) - } - }, - }, nil + DataSource: &testprovider.DataSource{ + ReadMethod: func(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var config struct { + TestComputed types.String `tfsdk:"test_computed"` + TestRequired types.String `tfsdk:"test_required"` + } + + resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &config)...) + + if config.TestRequired.Value != "test-config-value" { + resp.Diagnostics.AddError("unexpected req.ProviderMeta value: %s", config.TestRequired.Value) + } }, }, ProviderMeta: testConfig, @@ -141,6 +127,47 @@ func TestServerReadDataSource(t *testing.T) { State: testStateUnchanged, }, }, + "resource-configure-data": { + server: &fwserver.Server{ + DataSourceConfigureData: "test-provider-configure-value", + Provider: &testprovider.Provider{}, + }, + request: &fwserver.ReadDataSourceRequest{ + Config: testConfig, + DataSourceSchema: testSchema, + DataSource: &testprovider.DataSourceWithConfigure{ + ConfigureMethod: func(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + providerData, ok := req.ProviderData.(string) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected ConfigureRequest.ProviderData", + fmt.Sprintf("Expected string, got: %T", req.ProviderData), + ) + return + } + + if providerData != "test-provider-configure-value" { + resp.Diagnostics.AddError( + "Unexpected ConfigureRequest.ProviderData", + fmt.Sprintf("Expected test-provider-configure-value, got: %q", providerData), + ) + } + }, + DataSource: &testprovider.DataSource{ + ReadMethod: func(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + // In practice, the Configure method would save the + // provider data to the Resource implementation and + // use it here. The fact that Configure is able to + // read the data proves this can work. + }, + }, + }, + }, + expectedResponse: &fwserver.ReadDataSourceResponse{ + State: testStateUnchanged, + }, + }, "response-diagnostics": { server: &fwserver.Server{ Provider: &testprovider.Provider{}, @@ -148,17 +175,10 @@ func TestServerReadDataSource(t *testing.T) { request: &fwserver.ReadDataSourceRequest{ Config: testConfig, DataSourceSchema: testSchema, - DataSourceType: &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSource{ - ReadMethod: func(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil + DataSource: &testprovider.DataSource{ + ReadMethod: func(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") }, }, }, @@ -183,25 +203,18 @@ func TestServerReadDataSource(t *testing.T) { request: &fwserver.ReadDataSourceRequest{ Config: testConfig, DataSourceSchema: testSchema, - DataSourceType: &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSource{ - ReadMethod: func(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var data struct { - TestComputed types.String `tfsdk:"test_computed"` - TestRequired types.String `tfsdk:"test_required"` - } + DataSource: &testprovider.DataSource{ + ReadMethod: func(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data struct { + TestComputed types.String `tfsdk:"test_computed"` + TestRequired types.String `tfsdk:"test_required"` + } - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - data.TestComputed = types.String{Value: "test-state-value"} + data.TestComputed = types.String{Value: "test-state-value"} - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) - }, - }, nil + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) }, }, }, diff --git a/internal/fwserver/server_readresource.go b/internal/fwserver/server_readresource.go index f716c045a..ab94e447d 100644 --- a/internal/fwserver/server_readresource.go +++ b/internal/fwserver/server_readresource.go @@ -6,7 +6,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/tfsdk" ) @@ -15,7 +14,7 @@ import ( // ReadResource RPC. type ReadResourceRequest struct { CurrentState *tfsdk.State - ResourceType provider.ResourceType + Resource resource.Resource Private *privatestate.Data ProviderMeta *tfsdk.Config } @@ -44,15 +43,23 @@ func (s *Server) ReadResource(ctx context.Context, req *ReadResourceRequest, res return } - // Always instantiate new Resource instances. - logging.FrameworkDebug(ctx, "Calling provider defined ResourceType NewResource") - resourceImpl, diags := req.ResourceType.NewResource(ctx, s.Provider) - logging.FrameworkDebug(ctx, "Called provider defined ResourceType NewResource") + if _, ok := req.Resource.(resource.ResourceWithConfigure); ok { + logging.FrameworkTrace(ctx, "Resource implements ResourceWithConfigure") - resp.Diagnostics.Append(diags...) + configureReq := resource.ConfigureRequest{ + ProviderData: s.ResourceConfigureData, + } + configureResp := resource.ConfigureResponse{} - if resp.Diagnostics.HasError() { - return + logging.FrameworkDebug(ctx, "Calling provider defined Resource Configure") + req.Resource.(resource.ResourceWithConfigure).Configure(ctx, configureReq, &configureResp) + logging.FrameworkDebug(ctx, "Called provider defined Resource Configure") + + resp.Diagnostics.Append(configureResp.Diagnostics...) + + if resp.Diagnostics.HasError() { + return + } } readReq := resource.ReadRequest{ @@ -87,7 +94,7 @@ func (s *Server) ReadResource(ctx context.Context, req *ReadResourceRequest, res } logging.FrameworkDebug(ctx, "Calling provider defined Resource Read") - resourceImpl.Read(ctx, readReq, &readResp) + req.Resource.Read(ctx, readReq, &readResp) logging.FrameworkDebug(ctx, "Called provider defined Resource Read") resp.Diagnostics = readResp.Diagnostics diff --git a/internal/fwserver/server_readresource_test.go b/internal/fwserver/server_readresource_test.go index cab5de1ad..6bdd9a3a0 100644 --- a/internal/fwserver/server_readresource_test.go +++ b/internal/fwserver/server_readresource_test.go @@ -3,6 +3,7 @@ package fwserver_test import ( "bytes" "context" + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -12,7 +13,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" - "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" @@ -132,25 +132,18 @@ func TestServerReadResource(t *testing.T) { }, request: &fwserver.ReadResourceRequest{ CurrentState: testCurrentState, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - var data struct { - TestComputed types.String `tfsdk:"test_computed"` - TestRequired types.String `tfsdk:"test_required"` - } - - resp.Diagnostics.Append(req.State.Get(ctx, &data)...) - - if data.TestRequired.Value != "test-currentstate-value" { - resp.Diagnostics.AddError("unexpected req.State value: %s", data.TestRequired.Value) - } - }, - }, nil + Resource: &testprovider.Resource{ + ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data struct { + TestComputed types.String `tfsdk:"test_computed"` + TestRequired types.String `tfsdk:"test_required"` + } + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if data.TestRequired.Value != "test-currentstate-value" { + resp.Diagnostics.AddError("unexpected req.State value: %s", data.TestRequired.Value) + } }, }, }, @@ -165,25 +158,18 @@ func TestServerReadResource(t *testing.T) { }, request: &fwserver.ReadResourceRequest{ CurrentState: testCurrentState, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - var config struct { - TestComputed types.String `tfsdk:"test_computed"` - TestRequired types.String `tfsdk:"test_required"` - } - - resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &config)...) - - if config.TestRequired.Value != "test-currentstate-value" { - resp.Diagnostics.AddError("unexpected req.ProviderMeta value: %s", config.TestRequired.Value) - } - }, - }, nil + Resource: &testprovider.Resource{ + ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var config struct { + TestComputed types.String `tfsdk:"test_computed"` + TestRequired types.String `tfsdk:"test_required"` + } + + resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &config)...) + + if config.TestRequired.Value != "test-currentstate-value" { + resp.Diagnostics.AddError("unexpected req.ProviderMeta value: %s", config.TestRequired.Value) + } }, }, ProviderMeta: testConfig, @@ -199,25 +185,18 @@ func TestServerReadResource(t *testing.T) { }, request: &fwserver.ReadResourceRequest{ CurrentState: testCurrentState, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` + Resource: &testprovider.Resource{ + ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` - key := "providerKeyOne" - got, diags := req.Private.GetKey(ctx, key) + key := "providerKeyOne" + got, diags := req.Private.GetKey(ctx, key) - resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(diags...) - if string(got) != expected { - resp.Diagnostics.AddError("unexpected req.Private.Provider value: %s", string(got)) - } - }, - }, nil + if string(got) != expected { + resp.Diagnostics.AddError("unexpected req.Private.Provider value: %s", string(got)) + } }, }, Private: testPrivate, @@ -233,25 +212,59 @@ func TestServerReadResource(t *testing.T) { }, request: &fwserver.ReadResourceRequest{ CurrentState: testCurrentState, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - var expected []byte + Resource: &testprovider.Resource{ + ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var expected []byte - key := "providerKeyOne" - got, diags := req.Private.GetKey(ctx, key) + key := "providerKeyOne" + got, diags := req.Private.GetKey(ctx, key) - resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(diags...) - if !bytes.Equal(got, expected) { - resp.Diagnostics.AddError("unexpected req.Private.Provider value: %s", string(got)) - } - }, - }, nil + if !bytes.Equal(got, expected) { + resp.Diagnostics.AddError("unexpected req.Private.Provider value: %s", string(got)) + } + }, + }, + }, + expectedResponse: &fwserver.ReadResourceResponse{ + NewState: testCurrentState, + Private: testEmptyPrivate, + }, + }, + "resource-configure-data": { + server: &fwserver.Server{ + Provider: &testprovider.Provider{}, + ResourceConfigureData: "test-provider-configure-value", + }, + request: &fwserver.ReadResourceRequest{ + CurrentState: testCurrentState, + Resource: &testprovider.ResourceWithConfigure{ + ConfigureMethod: func(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + providerData, ok := req.ProviderData.(string) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected ConfigureRequest.ProviderData", + fmt.Sprintf("Expected string, got: %T", req.ProviderData), + ) + return + } + + if providerData != "test-provider-configure-value" { + resp.Diagnostics.AddError( + "Unexpected ConfigureRequest.ProviderData", + fmt.Sprintf("Expected test-provider-configure-value, got: %q", providerData), + ) + } + }, + Resource: &testprovider.Resource{ + ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + // In practice, the Configure method would save the + // provider data to the Resource implementation and + // use it here. The fact that Configure is able to + // read the data proves this can work. + }, }, }, }, @@ -266,17 +279,10 @@ func TestServerReadResource(t *testing.T) { }, request: &fwserver.ReadResourceRequest{ CurrentState: testCurrentState, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil + Resource: &testprovider.Resource{ + ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") }, }, }, @@ -301,25 +307,18 @@ func TestServerReadResource(t *testing.T) { }, request: &fwserver.ReadResourceRequest{ CurrentState: testCurrentState, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - var data struct { - TestComputed types.String `tfsdk:"test_computed"` - TestRequired types.String `tfsdk:"test_required"` - } + Resource: &testprovider.Resource{ + ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data struct { + TestComputed types.String `tfsdk:"test_computed"` + TestRequired types.String `tfsdk:"test_required"` + } - resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) - data.TestComputed = types.String{Value: "test-newstate-value"} + data.TestComputed = types.String{Value: "test-newstate-value"} - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) - }, - }, nil + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) }, }, }, @@ -334,16 +333,9 @@ func TestServerReadResource(t *testing.T) { }, request: &fwserver.ReadResourceRequest{ CurrentState: testCurrentState, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - resp.State.RemoveResource(ctx) - }, - }, nil + Resource: &testprovider.Resource{ + ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + resp.State.RemoveResource(ctx) }, }, }, @@ -358,18 +350,11 @@ func TestServerReadResource(t *testing.T) { }, request: &fwserver.ReadResourceRequest{ CurrentState: testCurrentState, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) - - resp.Diagnostics.Append(diags...) - }, - }, nil + Resource: &testprovider.Resource{ + ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) + + resp.Diagnostics.Append(diags...) }, }, }, @@ -384,18 +369,11 @@ func TestServerReadResource(t *testing.T) { }, request: &fwserver.ReadResourceRequest{ CurrentState: testCurrentState, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) - - resp.Diagnostics.Append(diags...) - }, - }, nil + Resource: &testprovider.Resource{ + ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) + + resp.Diagnostics.Append(diags...) }, }, Private: testPrivateFramework, diff --git a/internal/fwserver/server_updateresource.go b/internal/fwserver/server_updateresource.go index 78030c06d..ccc874145 100644 --- a/internal/fwserver/server_updateresource.go +++ b/internal/fwserver/server_updateresource.go @@ -9,7 +9,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/tfsdk" ) @@ -23,7 +22,7 @@ type UpdateResourceRequest struct { PriorState *tfsdk.State ProviderMeta *tfsdk.Config ResourceSchema fwschema.Schema - ResourceType provider.ResourceType + Resource resource.Resource } // UpdateResourceResponse is the framework server response for an update request @@ -41,15 +40,23 @@ func (s *Server) UpdateResource(ctx context.Context, req *UpdateResourceRequest, return } - // Always instantiate new Resource instances. - logging.FrameworkDebug(ctx, "Calling provider defined ResourceType NewResource") - resourceImpl, diags := req.ResourceType.NewResource(ctx, s.Provider) - logging.FrameworkDebug(ctx, "Called provider defined ResourceType NewResource") + if _, ok := req.Resource.(resource.ResourceWithConfigure); ok { + logging.FrameworkTrace(ctx, "Resource implements ResourceWithConfigure") - resp.Diagnostics.Append(diags...) + configureReq := resource.ConfigureRequest{ + ProviderData: s.ResourceConfigureData, + } + configureResp := resource.ConfigureResponse{} - if resp.Diagnostics.HasError() { - return + logging.FrameworkDebug(ctx, "Calling provider defined Resource Configure") + req.Resource.(resource.ResourceWithConfigure).Configure(ctx, configureReq, &configureResp) + logging.FrameworkDebug(ctx, "Called provider defined Resource Configure") + + resp.Diagnostics.Append(configureResp.Diagnostics...) + + if resp.Diagnostics.HasError() { + return + } } nullSchemaData := tftypes.NewValue(req.ResourceSchema.Type().TerraformType(ctx), nil) @@ -108,7 +115,7 @@ func (s *Server) UpdateResource(ctx context.Context, req *UpdateResourceRequest, } logging.FrameworkDebug(ctx, "Calling provider defined Resource Update") - resourceImpl.Update(ctx, updateReq, &updateResp) + req.Resource.Update(ctx, updateReq, &updateResp) logging.FrameworkDebug(ctx, "Called provider defined Resource Update") resp.Diagnostics = updateResp.Diagnostics diff --git a/internal/fwserver/server_updateresource_test.go b/internal/fwserver/server_updateresource_test.go index 143d44453..5c8e9dbfd 100644 --- a/internal/fwserver/server_updateresource_test.go +++ b/internal/fwserver/server_updateresource_test.go @@ -13,7 +13,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" - "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" @@ -136,22 +135,15 @@ func TestServerUpdateResource(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var data testSchemaData - - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - - if data.TestRequired.Value != "test-new-value" { - resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) - } - }, - }, nil + Resource: &testprovider.Resource{ + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data testSchemaData + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if data.TestRequired.Value != "test-new-value" { + resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) + } }, }, }, @@ -194,22 +186,15 @@ func TestServerUpdateResource(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var data testSchemaData - - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - - if data.TestComputed.Value != "test-plannedstate-value" { - resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestComputed.Value) - } - }, - }, nil + Resource: &testprovider.Resource{ + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data testSchemaData + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if data.TestComputed.Value != "test-plannedstate-value" { + resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestComputed.Value) + } }, }, }, @@ -252,22 +237,15 @@ func TestServerUpdateResource(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var data testSchemaData - - resp.Diagnostics.Append(req.State.Get(ctx, &data)...) - - if data.TestRequired.Value != "test-old-value" { - resp.Diagnostics.AddError("Unexpected req.State Value", "Got: "+data.TestRequired.Value) - } - }, - }, nil + Resource: &testprovider.Resource{ + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data testSchemaData + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if data.TestRequired.Value != "test-old-value" { + resp.Diagnostics.AddError("Unexpected req.State Value", "Got: "+data.TestRequired.Value) + } }, }, }, @@ -311,22 +289,15 @@ func TestServerUpdateResource(t *testing.T) { }, ProviderMeta: testProviderMetaConfig, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var data testProviderMetaData - - resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) - - if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { - resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) - } - }, - }, nil + Resource: &testprovider.Resource{ + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data testProviderMetaData + + resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) + + if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { + resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) + } }, }, }, @@ -355,26 +326,19 @@ func TestServerUpdateResource(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` - got, diags := req.Private.GetKey(ctx, "providerKeyOne") - - resp.Diagnostics.Append(diags...) - - if string(got) != expected { - resp.Diagnostics.AddError( - "Unexpected req.Private Value", - fmt.Sprintf("expected %q, got %q", expected, got), - ) - } - }, - }, nil + Resource: &testprovider.Resource{ + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` + got, diags := req.Private.GetKey(ctx, "providerKeyOne") + + resp.Diagnostics.Append(diags...) + + if string(got) != expected { + resp.Diagnostics.AddError( + "Unexpected req.Private Value", + fmt.Sprintf("expected %q, got %q", expected, got), + ) + } }, }, PlannedPrivate: &privatestate.Data{ @@ -407,26 +371,19 @@ func TestServerUpdateResource(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var expected []byte - got, diags := req.Private.GetKey(ctx, "providerKeyOne") - - resp.Diagnostics.Append(diags...) - - if !bytes.Equal(got, expected) { - resp.Diagnostics.AddError( - "Unexpected req.Private Value", - fmt.Sprintf("expected %q, got %q", expected, got), - ) - } - }, - }, nil + Resource: &testprovider.Resource{ + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var expected []byte + got, diags := req.Private.GetKey(ctx, "providerKeyOne") + + resp.Diagnostics.Append(diags...) + + if !bytes.Equal(got, expected) { + resp.Diagnostics.AddError( + "Unexpected req.Private Value", + fmt.Sprintf("expected %q, got %q", expected, got), + ) + } }, }, }, @@ -441,6 +398,65 @@ func TestServerUpdateResource(t *testing.T) { Private: testEmptyPrivate, }, }, + "resource-configure-data": { + server: &fwserver.Server{ + Provider: &testprovider.Provider{}, + ResourceConfigureData: "test-provider-configure-value", + }, + request: &fwserver.UpdateResourceRequest{ + PlannedState: &tfsdk.Plan{ + Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{ + "test_computed": tftypes.NewValue(tftypes.String, nil), + "test_required": tftypes.NewValue(tftypes.String, "test-plannedstate-value"), + }), + Schema: testSchema, + }, + ResourceSchema: testSchema, + Resource: &testprovider.ResourceWithConfigure{ + ConfigureMethod: func(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + providerData, ok := req.ProviderData.(string) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected ConfigureRequest.ProviderData", + fmt.Sprintf("Expected string, got: %T", req.ProviderData), + ) + return + } + + if providerData != "test-provider-configure-value" { + resp.Diagnostics.AddError( + "Unexpected ConfigureRequest.ProviderData", + fmt.Sprintf("Expected test-provider-configure-value, got: %q", providerData), + ) + } + }, + Resource: &testprovider.Resource{ + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + // In practice, the Configure method would save the + // provider data to the Resource implementation and + // use it here. The fact that Configure is able to + // read the data proves this can work. + + var data testSchemaData + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + }, + }, + }, + }, + expectedResponse: &fwserver.UpdateResourceResponse{ + NewState: &tfsdk.State{ + Raw: tftypes.NewValue(testSchemaType, map[string]tftypes.Value{ + "test_computed": tftypes.NewValue(tftypes.String, nil), + "test_required": tftypes.NewValue(tftypes.String, "test-plannedstate-value"), + }), + Schema: testSchema, + }, + Private: testEmptyPrivate, + }, + }, "response-diagnostics": { server: &fwserver.Server{ Provider: &testprovider.Provider{}, @@ -468,17 +484,10 @@ func TestServerUpdateResource(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil + Resource: &testprovider.Resource{ + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") }, }, }, @@ -530,19 +539,12 @@ func TestServerUpdateResource(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var data testSchemaData - - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) - }, - }, nil + Resource: &testprovider.Resource{ + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data testSchemaData + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) }, }, }, @@ -584,16 +586,9 @@ func TestServerUpdateResource(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - resp.State.RemoveResource(ctx) - }, - }, nil + Resource: &testprovider.Resource{ + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.State.RemoveResource(ctx) }, }, }, @@ -625,18 +620,11 @@ func TestServerUpdateResource(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) - - resp.Diagnostics.Append(diags...) - }, - }, nil + Resource: &testprovider.Resource{ + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) + + resp.Diagnostics.Append(diags...) }, }, }, @@ -664,18 +652,11 @@ func TestServerUpdateResource(t *testing.T) { Schema: testSchema, }, ResourceSchema: testSchema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ - UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) - - resp.Diagnostics.Append(diags...) - }, - }, nil + Resource: &testprovider.Resource{ + UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + diags := resp.Private.SetKey(ctx, "providerKeyOne", []byte(`{"pKeyOne": {"k0": "zero", "k1": 1}}`)) + + resp.Diagnostics.Append(diags...) }, }, PlannedPrivate: testPrivateFramework, diff --git a/internal/fwserver/server_upgraderesourcestate.go b/internal/fwserver/server_upgraderesourcestate.go index 54031ef46..0d8370f07 100644 --- a/internal/fwserver/server_upgraderesourcestate.go +++ b/internal/fwserver/server_upgraderesourcestate.go @@ -10,7 +10,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/logging" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/tfsdk" ) @@ -23,7 +22,7 @@ type UpgradeResourceStateRequest struct { RawState *tfprotov6.RawState ResourceSchema fwschema.Schema - ResourceType provider.ResourceType + Resource resource.Resource Version int64 } @@ -100,18 +99,26 @@ func (s *Server) UpgradeResourceState(ctx context.Context, req *UpgradeResourceS return } - // Always instantiate new Resource instances. - logging.FrameworkDebug(ctx, "Calling provider defined ResourceType NewResource") - resourceImpl, diags := req.ResourceType.NewResource(ctx, s.Provider) - logging.FrameworkDebug(ctx, "Called provider defined ResourceType NewResource") + if _, ok := req.Resource.(resource.ResourceWithConfigure); ok { + logging.FrameworkTrace(ctx, "Resource implements ResourceWithConfigure") - resp.Diagnostics.Append(diags...) + configureReq := resource.ConfigureRequest{ + ProviderData: s.ResourceConfigureData, + } + configureResp := resource.ConfigureResponse{} - if resp.Diagnostics.HasError() { - return + logging.FrameworkDebug(ctx, "Calling provider defined Resource Configure") + req.Resource.(resource.ResourceWithConfigure).Configure(ctx, configureReq, &configureResp) + logging.FrameworkDebug(ctx, "Called provider defined Resource Configure") + + resp.Diagnostics.Append(configureResp.Diagnostics...) + + if resp.Diagnostics.HasError() { + return + } } - resourceWithUpgradeState, ok := resourceImpl.(resource.ResourceWithUpgradeState) + resourceWithUpgradeState, ok := req.Resource.(resource.ResourceWithUpgradeState) if !ok { resp.Diagnostics.AddError( diff --git a/internal/fwserver/server_upgraderesourcestate_test.go b/internal/fwserver/server_upgraderesourcestate_test.go index d7222adc3..da22756ad 100644 --- a/internal/fwserver/server_upgraderesourcestate_test.go +++ b/internal/fwserver/server_upgraderesourcestate_test.go @@ -14,7 +14,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" "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" @@ -54,13 +53,114 @@ func TestServerUpgradeResourceState(t *testing.T) { }, expectedResponse: &fwserver.UpgradeResourceStateResponse{}, }, + "resource-configure-data": { + server: &fwserver.Server{ + Provider: &testprovider.Provider{}, + ResourceConfigureData: "test-provider-configure-value", + }, + request: &fwserver.UpgradeResourceStateRequest{ + RawState: testNewRawState(t, map[string]interface{}{ + "id": "test-id-value", + "required_attribute": true, + }), + ResourceSchema: schema, + Resource: &testprovider.ResourceWithConfigureAndUpgradeState{ + ConfigureMethod: func(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + providerData, ok := req.ProviderData.(string) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected ConfigureRequest.ProviderData", + fmt.Sprintf("Expected string, got: %T", req.ProviderData), + ) + return + } + + if providerData != "test-provider-configure-value" { + resp.Diagnostics.AddError( + "Unexpected ConfigureRequest.ProviderData", + fmt.Sprintf("Expected test-provider-configure-value, got: %q", providerData), + ) + } + }, + Resource: &testprovider.Resource{}, + UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{ + 0: { + PriorSchema: &tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "id": { + Type: types.StringType, + Computed: true, + }, + "optional_attribute": { + Type: types.BoolType, + Optional: true, + }, + "required_attribute": { + Type: types.BoolType, + Required: true, + }, + }, + }, + StateUpgrader: func(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { + // In practice, the Configure method would save the + // provider data to the Resource implementation and + // use it here. The fact that Configure is able to + // read the data proves this can work. + + var priorStateData struct { + Id string `tfsdk:"id"` + OptionalAttribute *bool `tfsdk:"optional_attribute"` + RequiredAttribute bool `tfsdk:"required_attribute"` + } + + resp.Diagnostics.Append(req.State.Get(ctx, &priorStateData)...) + + if resp.Diagnostics.HasError() { + return + } + + upgradedStateData := struct { + Id string `tfsdk:"id"` + OptionalAttribute *string `tfsdk:"optional_attribute"` + RequiredAttribute string `tfsdk:"required_attribute"` + }{ + Id: priorStateData.Id, + RequiredAttribute: fmt.Sprintf("%t", priorStateData.RequiredAttribute), + } + + if priorStateData.OptionalAttribute != nil { + v := fmt.Sprintf("%t", *priorStateData.OptionalAttribute) + upgradedStateData.OptionalAttribute = &v + } + + resp.Diagnostics.Append(resp.State.Set(ctx, upgradedStateData)...) + }, + }, + } + }, + }, + Version: 0, + }, + expectedResponse: &fwserver.UpgradeResourceStateResponse{ + UpgradedState: &tfsdk.State{ + Raw: tftypes.NewValue(schemaType, map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "test-id-value"), + "optional_attribute": tftypes.NewValue(tftypes.String, nil), + "required_attribute": tftypes.NewValue(tftypes.String, "true"), + }), + Schema: schema, + }, + }, + }, "RawState-missing": { server: &fwserver.Server{ Provider: &testprovider.Provider{}, }, request: &fwserver.UpgradeResourceStateRequest{ ResourceSchema: schema, - ResourceType: &testprovider.ResourceType{}, + Resource: &testprovider.Resource{}, Version: 0, }, expectedResponse: &fwserver.UpgradeResourceStateResponse{}, @@ -75,95 +175,88 @@ func TestServerUpgradeResourceState(t *testing.T) { "required_attribute": true, }), ResourceSchema: schema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithUpgradeState{ - Resource: &testprovider.Resource{}, - UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { - return map[int64]resource.StateUpgrader{ - 0: { - StateUpgrader: func(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { - rawStateValue, err := req.RawState.Unmarshal(tftypes.Object{ - AttributeTypes: map[string]tftypes.Type{ - "id": tftypes.String, - "optional_attribute": tftypes.Bool, - "required_attribute": tftypes.Bool, - }, - }) - - if err != nil { - resp.Diagnostics.AddError( - "Unable to Unmarshal Prior State", - err.Error(), - ) - return - } - - var rawState map[string]tftypes.Value - - if err := rawStateValue.As(&rawState); err != nil { - resp.Diagnostics.AddError( - "Unable to Convert Prior State", - err.Error(), - ) - return - } - - var optionalAttributeString *string - - if !rawState["optional_attribute"].IsNull() { - var optionalAttribute bool - - if err := rawState["optional_attribute"].As(&optionalAttribute); err != nil { - resp.Diagnostics.AddAttributeError( - path.Root("optional_attribute"), - "Unable to Convert Prior State", - err.Error(), - ) - return - } - - v := fmt.Sprintf("%t", optionalAttribute) - optionalAttributeString = &v - } - - var requiredAttribute bool - - if err := rawState["required_attribute"].As(&requiredAttribute); err != nil { - resp.Diagnostics.AddAttributeError( - path.Root("required_attribute"), - "Unable to Convert Prior State", - err.Error(), - ) - return - } - - dynamicValue, err := tfprotov6.NewDynamicValue( - schemaType, - tftypes.NewValue(schemaType, map[string]tftypes.Value{ - "id": rawState["id"], - "optional_attribute": tftypes.NewValue(tftypes.String, optionalAttributeString), - "required_attribute": tftypes.NewValue(tftypes.String, fmt.Sprintf("%t", requiredAttribute)), - }), - ) - - if err != nil { - resp.Diagnostics.AddError( - "Unable to Convert Upgraded State", - err.Error(), - ) - return - } - - resp.DynamicValue = &dynamicValue + Resource: &testprovider.ResourceWithUpgradeState{ + Resource: &testprovider.Resource{}, + UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{ + 0: { + StateUpgrader: func(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { + rawStateValue, err := req.RawState.Unmarshal(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "id": tftypes.String, + "optional_attribute": tftypes.Bool, + "required_attribute": tftypes.Bool, }, - }, - } + }) + + if err != nil { + resp.Diagnostics.AddError( + "Unable to Unmarshal Prior State", + err.Error(), + ) + return + } + + var rawState map[string]tftypes.Value + + if err := rawStateValue.As(&rawState); err != nil { + resp.Diagnostics.AddError( + "Unable to Convert Prior State", + err.Error(), + ) + return + } + + var optionalAttributeString *string + + if !rawState["optional_attribute"].IsNull() { + var optionalAttribute bool + + if err := rawState["optional_attribute"].As(&optionalAttribute); err != nil { + resp.Diagnostics.AddAttributeError( + path.Root("optional_attribute"), + "Unable to Convert Prior State", + err.Error(), + ) + return + } + + v := fmt.Sprintf("%t", optionalAttribute) + optionalAttributeString = &v + } + + var requiredAttribute bool + + if err := rawState["required_attribute"].As(&requiredAttribute); err != nil { + resp.Diagnostics.AddAttributeError( + path.Root("required_attribute"), + "Unable to Convert Prior State", + err.Error(), + ) + return + } + + dynamicValue, err := tfprotov6.NewDynamicValue( + schemaType, + tftypes.NewValue(schemaType, map[string]tftypes.Value{ + "id": rawState["id"], + "optional_attribute": tftypes.NewValue(tftypes.String, optionalAttributeString), + "required_attribute": tftypes.NewValue(tftypes.String, fmt.Sprintf("%t", requiredAttribute)), + }), + ) + + if err != nil { + resp.Diagnostics.AddError( + "Unable to Convert Upgraded State", + err.Error(), + ) + return + } + + resp.DynamicValue = &dynamicValue + }, }, - }, nil + } }, }, Version: 0, @@ -189,61 +282,54 @@ func TestServerUpgradeResourceState(t *testing.T) { "required_attribute": true, }), ResourceSchema: schema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithUpgradeState{ - Resource: &testprovider.Resource{}, - UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { - return map[int64]resource.StateUpgrader{ - 0: { - StateUpgrader: func(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { - var rawState struct { - Id string `json:"id"` - OptionalAttribute *bool `json:"optional_attribute,omitempty"` - RequiredAttribute bool `json:"required_attribute"` - } - - if err := json.Unmarshal(req.RawState.JSON, &rawState); err != nil { - resp.Diagnostics.AddError( - "Unable to Unmarshal Prior State", - err.Error(), - ) - return - } - - var optionalAttribute *string - - if rawState.OptionalAttribute != nil { - v := fmt.Sprintf("%t", *rawState.OptionalAttribute) - optionalAttribute = &v - } - - dynamicValue, err := tfprotov6.NewDynamicValue( - schemaType, - tftypes.NewValue(schemaType, map[string]tftypes.Value{ - "id": tftypes.NewValue(tftypes.String, rawState.Id), - "optional_attribute": tftypes.NewValue(tftypes.String, optionalAttribute), - "required_attribute": tftypes.NewValue(tftypes.String, fmt.Sprintf("%t", rawState.RequiredAttribute)), - }), - ) - - if err != nil { - resp.Diagnostics.AddError( - "Unable to Create Upgraded State", - err.Error(), - ) - return - } - - resp.DynamicValue = &dynamicValue - }, - }, - } + Resource: &testprovider.ResourceWithUpgradeState{ + Resource: &testprovider.Resource{}, + UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{ + 0: { + StateUpgrader: func(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { + var rawState struct { + Id string `json:"id"` + OptionalAttribute *bool `json:"optional_attribute,omitempty"` + RequiredAttribute bool `json:"required_attribute"` + } + + if err := json.Unmarshal(req.RawState.JSON, &rawState); err != nil { + resp.Diagnostics.AddError( + "Unable to Unmarshal Prior State", + err.Error(), + ) + return + } + + var optionalAttribute *string + + if rawState.OptionalAttribute != nil { + v := fmt.Sprintf("%t", *rawState.OptionalAttribute) + optionalAttribute = &v + } + + dynamicValue, err := tfprotov6.NewDynamicValue( + schemaType, + tftypes.NewValue(schemaType, map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, rawState.Id), + "optional_attribute": tftypes.NewValue(tftypes.String, optionalAttribute), + "required_attribute": tftypes.NewValue(tftypes.String, fmt.Sprintf("%t", rawState.RequiredAttribute)), + }), + ) + + if err != nil { + resp.Diagnostics.AddError( + "Unable to Create Upgraded State", + err.Error(), + ) + return + } + + resp.DynamicValue = &dynamicValue + }, }, - }, nil + } }, }, Version: 0, @@ -269,15 +355,8 @@ func TestServerUpgradeResourceState(t *testing.T) { "required_attribute": true, }), ResourceSchema: schema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, - }, - Version: 0, + Resource: &testprovider.Resource{}, + Version: 0, }, expectedResponse: &fwserver.UpgradeResourceStateResponse{ Diagnostics: diag.Diagnostics{ @@ -300,17 +379,10 @@ func TestServerUpgradeResourceState(t *testing.T) { "required_attribute": true, }), ResourceSchema: schema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithUpgradeState{ - Resource: &testprovider.Resource{}, - UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { - return nil - }, - }, nil + Resource: &testprovider.ResourceWithUpgradeState{ + Resource: &testprovider.Resource{}, + UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { + return nil }, }, Version: 0, @@ -336,39 +408,32 @@ func TestServerUpgradeResourceState(t *testing.T) { "required_attribute": true, }), ResourceSchema: schema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithUpgradeState{ - Resource: &testprovider.Resource{}, - UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { - return map[int64]resource.StateUpgrader{ - 0: { - PriorSchema: &tfsdk.Schema{ - Attributes: map[string]tfsdk.Attribute{ - "id": { - Type: types.StringType, - Computed: true, - }, - "optional_attribute": { - Type: types.Int64Type, // Purposefully incorrect - Optional: true, - }, - "required_attribute": { - Type: types.Int64Type, // Purposefully incorrect - Required: true, - }, - }, + Resource: &testprovider.ResourceWithUpgradeState{ + Resource: &testprovider.Resource{}, + UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{ + 0: { + PriorSchema: &tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "id": { + Type: types.StringType, + Computed: true, + }, + "optional_attribute": { + Type: types.Int64Type, // Purposefully incorrect + Optional: true, }, - StateUpgrader: func(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { - // Expect error before reaching this logic. + "required_attribute": { + Type: types.Int64Type, // Purposefully incorrect + Required: true, }, }, - } + }, + StateUpgrader: func(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { + // Expect error before reaching this logic. + }, }, - }, nil + } }, }, Version: 0, @@ -394,65 +459,58 @@ func TestServerUpgradeResourceState(t *testing.T) { "required_attribute": true, }), ResourceSchema: schema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithUpgradeState{ - Resource: &testprovider.Resource{}, - UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { - return map[int64]resource.StateUpgrader{ - 0: { - PriorSchema: &tfsdk.Schema{ - Attributes: map[string]tfsdk.Attribute{ - "id": { - Type: types.StringType, - Computed: true, - }, - "optional_attribute": { - Type: types.BoolType, - Optional: true, - }, - "required_attribute": { - Type: types.BoolType, - Required: true, - }, - }, + Resource: &testprovider.ResourceWithUpgradeState{ + Resource: &testprovider.Resource{}, + UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{ + 0: { + PriorSchema: &tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "id": { + Type: types.StringType, + Computed: true, + }, + "optional_attribute": { + Type: types.BoolType, + Optional: true, }, - StateUpgrader: func(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { - var priorStateData struct { - Id string `tfsdk:"id"` - OptionalAttribute *bool `tfsdk:"optional_attribute"` - RequiredAttribute bool `tfsdk:"required_attribute"` - } - - resp.Diagnostics.Append(req.State.Get(ctx, &priorStateData)...) - - if resp.Diagnostics.HasError() { - return - } - - upgradedStateData := struct { - Id string `tfsdk:"id"` - OptionalAttribute *string `tfsdk:"optional_attribute"` - RequiredAttribute string `tfsdk:"required_attribute"` - }{ - Id: priorStateData.Id, - RequiredAttribute: fmt.Sprintf("%t", priorStateData.RequiredAttribute), - } - - if priorStateData.OptionalAttribute != nil { - v := fmt.Sprintf("%t", *priorStateData.OptionalAttribute) - upgradedStateData.OptionalAttribute = &v - } - - resp.Diagnostics.Append(resp.State.Set(ctx, upgradedStateData)...) + "required_attribute": { + Type: types.BoolType, + Required: true, }, }, - } + }, + StateUpgrader: func(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { + var priorStateData struct { + Id string `tfsdk:"id"` + OptionalAttribute *bool `tfsdk:"optional_attribute"` + RequiredAttribute bool `tfsdk:"required_attribute"` + } + + resp.Diagnostics.Append(req.State.Get(ctx, &priorStateData)...) + + if resp.Diagnostics.HasError() { + return + } + + upgradedStateData := struct { + Id string `tfsdk:"id"` + OptionalAttribute *string `tfsdk:"optional_attribute"` + RequiredAttribute string `tfsdk:"required_attribute"` + }{ + Id: priorStateData.Id, + RequiredAttribute: fmt.Sprintf("%t", priorStateData.RequiredAttribute), + } + + if priorStateData.OptionalAttribute != nil { + v := fmt.Sprintf("%t", *priorStateData.OptionalAttribute) + upgradedStateData.OptionalAttribute = &v + } + + resp.Diagnostics.Append(resp.State.Set(ctx, upgradedStateData)...) + }, }, - }, nil + } }, }, Version: 0, @@ -479,65 +537,58 @@ func TestServerUpgradeResourceState(t *testing.T) { "nonexistent_attribute": "value", }), ResourceSchema: schema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithUpgradeState{ - Resource: &testprovider.Resource{}, - UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { - return map[int64]resource.StateUpgrader{ - 0: { - PriorSchema: &tfsdk.Schema{ - Attributes: map[string]tfsdk.Attribute{ - "id": { - Type: types.StringType, - Computed: true, - }, - "optional_attribute": { - Type: types.BoolType, - Optional: true, - }, - "required_attribute": { - Type: types.BoolType, - Required: true, - }, - }, + Resource: &testprovider.ResourceWithUpgradeState{ + Resource: &testprovider.Resource{}, + UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{ + 0: { + PriorSchema: &tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "id": { + Type: types.StringType, + Computed: true, }, - StateUpgrader: func(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { - var priorStateData struct { - Id string `tfsdk:"id"` - OptionalAttribute *bool `tfsdk:"optional_attribute"` - RequiredAttribute bool `tfsdk:"required_attribute"` - } - - resp.Diagnostics.Append(req.State.Get(ctx, &priorStateData)...) - - if resp.Diagnostics.HasError() { - return - } - - upgradedStateData := struct { - Id string `tfsdk:"id"` - OptionalAttribute *string `tfsdk:"optional_attribute"` - RequiredAttribute string `tfsdk:"required_attribute"` - }{ - Id: priorStateData.Id, - RequiredAttribute: fmt.Sprintf("%t", priorStateData.RequiredAttribute), - } - - if priorStateData.OptionalAttribute != nil { - v := fmt.Sprintf("%t", *priorStateData.OptionalAttribute) - upgradedStateData.OptionalAttribute = &v - } - - resp.Diagnostics.Append(resp.State.Set(ctx, upgradedStateData)...) + "optional_attribute": { + Type: types.BoolType, + Optional: true, + }, + "required_attribute": { + Type: types.BoolType, + Required: true, }, }, - } + }, + StateUpgrader: func(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { + var priorStateData struct { + Id string `tfsdk:"id"` + OptionalAttribute *bool `tfsdk:"optional_attribute"` + RequiredAttribute bool `tfsdk:"required_attribute"` + } + + resp.Diagnostics.Append(req.State.Get(ctx, &priorStateData)...) + + if resp.Diagnostics.HasError() { + return + } + + upgradedStateData := struct { + Id string `tfsdk:"id"` + OptionalAttribute *string `tfsdk:"optional_attribute"` + RequiredAttribute string `tfsdk:"required_attribute"` + }{ + Id: priorStateData.Id, + RequiredAttribute: fmt.Sprintf("%t", priorStateData.RequiredAttribute), + } + + if priorStateData.OptionalAttribute != nil { + v := fmt.Sprintf("%t", *priorStateData.OptionalAttribute) + upgradedStateData.OptionalAttribute = &v + } + + resp.Diagnostics.Append(resp.State.Set(ctx, upgradedStateData)...) + }, }, - }, nil + } }, }, Version: 0, @@ -563,23 +614,16 @@ func TestServerUpgradeResourceState(t *testing.T) { "required_attribute": true, }), ResourceSchema: schema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithUpgradeState{ - Resource: &testprovider.Resource{}, - UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { - return map[int64]resource.StateUpgrader{ - 0: { - StateUpgrader: func(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { - // Purposfully not setting resp.DynamicValue or resp.State - }, - }, - } + Resource: &testprovider.ResourceWithUpgradeState{ + Resource: &testprovider.Resource{}, + UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{ + 0: { + StateUpgrader: func(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { + // Purposfully not setting resp.DynamicValue or resp.State + }, }, - }, nil + } }, }, Version: 0, @@ -598,14 +642,19 @@ func TestServerUpgradeResourceState(t *testing.T) { "Version-current-flatmap": { server: &fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return schema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + } }, - }, nil + } }, }, }, @@ -616,16 +665,8 @@ func TestServerUpgradeResourceState(t *testing.T) { }, }, ResourceSchema: schema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - // Framework should allow non-ResourceWithUpgradeState - return &testprovider.Resource{}, nil - }, - }, - Version: 1, // Must match current tfsdk.Schema version to trigger framework implementation + Resource: &testprovider.Resource{}, + Version: 1, // Must match current tfsdk.Schema version to trigger framework implementation }, expectedResponse: &fwserver.UpgradeResourceStateResponse{ Diagnostics: diag.Diagnostics{ @@ -643,14 +684,19 @@ func TestServerUpgradeResourceState(t *testing.T) { "Version-current-json-match": { server: &fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return schema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + } }, - }, nil + } }, }, }, @@ -660,16 +706,8 @@ func TestServerUpgradeResourceState(t *testing.T) { "required_attribute": "true", }), ResourceSchema: schema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - // Framework should allow non-ResourceWithUpgradeState - return &testprovider.Resource{}, nil - }, - }, - Version: 1, // Must match current tfsdk.Schema version to trigger framework implementation + Resource: &testprovider.Resource{}, + Version: 1, // Must match current tfsdk.Schema version to trigger framework implementation }, expectedResponse: &fwserver.UpgradeResourceStateResponse{ UpgradedState: &tfsdk.State{ @@ -693,16 +731,8 @@ func TestServerUpgradeResourceState(t *testing.T) { "nonexistent_attribute": "value", }), ResourceSchema: schema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - // Framework should allow non-ResourceWithUpgradeState - return &testprovider.Resource{}, nil - }, - }, - Version: 1, // Must match current tfsdk.Schema version to trigger framework implementation + Resource: &testprovider.Resource{}, + Version: 1, // Must match current tfsdk.Schema version to trigger framework implementation }, expectedResponse: &fwserver.UpgradeResourceStateResponse{ UpgradedState: &tfsdk.State{ @@ -725,17 +755,10 @@ func TestServerUpgradeResourceState(t *testing.T) { "required_attribute": true, }), ResourceSchema: schema, - ResourceType: &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithUpgradeState{ - Resource: &testprovider.Resource{}, - UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { - return nil - }, - }, nil + Resource: &testprovider.ResourceWithUpgradeState{ + Resource: &testprovider.Resource{}, + UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { + return nil }, }, Version: 999, diff --git a/internal/fwserver/server_validatedatasourceconfig.go b/internal/fwserver/server_validatedatasourceconfig.go index f8a76b4e2..03b496d1d 100644 --- a/internal/fwserver/server_validatedatasourceconfig.go +++ b/internal/fwserver/server_validatedatasourceconfig.go @@ -6,15 +6,14 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/logging" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/tfsdk" ) // ValidateDataSourceConfigRequest is the framework server request for the // ValidateDataSourceConfig RPC. type ValidateDataSourceConfigRequest struct { - Config *tfsdk.Config - DataSourceType provider.DataSourceType + Config *tfsdk.Config + DataSource datasource.DataSource } // ValidateDataSourceConfigResponse is the framework server response for the @@ -29,22 +28,30 @@ func (s *Server) ValidateDataSourceConfig(ctx context.Context, req *ValidateData return } - // Always instantiate new DataSource instances. - logging.FrameworkDebug(ctx, "Calling provider defined DataSourceType NewDataSource") - dataSource, diags := req.DataSourceType.NewDataSource(ctx, s.Provider) - logging.FrameworkDebug(ctx, "Called provider defined DataSourceType NewDataSource") + if _, ok := req.DataSource.(datasource.DataSourceWithConfigure); ok { + logging.FrameworkTrace(ctx, "DataSource implements DataSourceWithConfigure") - resp.Diagnostics.Append(diags...) + configureReq := datasource.ConfigureRequest{ + ProviderData: s.DataSourceConfigureData, + } + configureResp := datasource.ConfigureResponse{} - if resp.Diagnostics.HasError() { - return + logging.FrameworkDebug(ctx, "Calling provider defined DataSource Configure") + req.DataSource.(datasource.DataSourceWithConfigure).Configure(ctx, configureReq, &configureResp) + logging.FrameworkDebug(ctx, "Called provider defined DataSource Configure") + + resp.Diagnostics.Append(configureResp.Diagnostics...) + + if resp.Diagnostics.HasError() { + return + } } vdscReq := datasource.ValidateConfigRequest{ Config: *req.Config, } - if dataSource, ok := dataSource.(datasource.DataSourceWithConfigValidators); ok { + if dataSource, ok := req.DataSource.(datasource.DataSourceWithConfigValidators); ok { logging.FrameworkTrace(ctx, "DataSource implements DataSourceWithConfigValidators") for _, configValidator := range dataSource.ConfigValidators(ctx) { @@ -72,7 +79,7 @@ func (s *Server) ValidateDataSourceConfig(ctx context.Context, req *ValidateData } } - if dataSource, ok := dataSource.(datasource.DataSourceWithValidateConfig); ok { + if dataSource, ok := req.DataSource.(datasource.DataSourceWithValidateConfig); ok { logging.FrameworkTrace(ctx, "DataSource implements DataSourceWithValidateConfig") vdscResp := &datasource.ValidateConfigResponse{ diff --git a/internal/fwserver/server_validatedatasourceconfig_test.go b/internal/fwserver/server_validatedatasourceconfig_test.go index 3f3c0269a..7b914ede2 100644 --- a/internal/fwserver/server_validatedatasourceconfig_test.go +++ b/internal/fwserver/server_validatedatasourceconfig_test.go @@ -10,7 +10,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" "github.com/hashicorp/terraform-plugin-framework/path" - "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-go/tftypes" @@ -112,7 +111,7 @@ func TestServerValidateDataSourceConfig(t *testing.T) { }, request: &fwserver.ValidateDataSourceConfigRequest{ Config: &testConfig, - DataSourceType: &testprovider.DataSourceType{ + DataSource: &testprovider.DataSourceWithGetSchema{ GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return testSchema, nil }, @@ -126,7 +125,7 @@ func TestServerValidateDataSourceConfig(t *testing.T) { }, request: &fwserver.ValidateDataSourceConfigRequest{ Config: &testConfigAttributeValidator, - DataSourceType: &testprovider.DataSourceType{ + DataSource: &testprovider.DataSourceWithGetSchema{ GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return testSchemaAttributeValidator, nil }, @@ -140,7 +139,7 @@ func TestServerValidateDataSourceConfig(t *testing.T) { }, request: &fwserver.ValidateDataSourceConfigRequest{ Config: &testConfigAttributeValidatorError, - DataSourceType: &testprovider.DataSourceType{ + DataSource: &testprovider.DataSourceWithGetSchema{ GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return testSchemaAttributeValidatorError, nil }, @@ -162,33 +161,29 @@ func TestServerValidateDataSourceConfig(t *testing.T) { }, request: &fwserver.ValidateDataSourceConfigRequest{ Config: &testConfig, - DataSourceType: &testprovider.DataSourceType{ + DataSource: &testprovider.DataSourceWithConfigValidatorsAndGetSchemaAndMetadata{ GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return testSchema, nil }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSourceWithConfigValidators{ - DataSource: &testprovider.DataSource{}, - ConfigValidatorsMethod: func(ctx context.Context) []datasource.ConfigValidator { - return []datasource.ConfigValidator{ - &testprovider.DataSourceConfigValidator{ - ValidateDataSourceMethod: func(ctx context.Context, req datasource.ValidateConfigRequest, resp *datasource.ValidateConfigResponse) { - var got types.String + DataSource: &testprovider.DataSource{}, + ConfigValidatorsMethod: func(ctx context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{ + &testprovider.DataSourceConfigValidator{ + ValidateDataSourceMethod: func(ctx context.Context, req datasource.ValidateConfigRequest, resp *datasource.ValidateConfigResponse) { + var got types.String - resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("test"), &got)...) + resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("test"), &got)...) - if resp.Diagnostics.HasError() { - return - } + if resp.Diagnostics.HasError() { + return + } - if got.Value != "test-value" { - resp.Diagnostics.AddError("Incorrect req.Config", "expected test-value, got "+got.Value) - } - }, - }, - } + if got.Value != "test-value" { + resp.Diagnostics.AddError("Incorrect req.Config", "expected test-value, got "+got.Value) + } + }, }, - }, nil + } }, }, }, @@ -200,23 +195,19 @@ func TestServerValidateDataSourceConfig(t *testing.T) { }, request: &fwserver.ValidateDataSourceConfigRequest{ Config: &testConfig, - DataSourceType: &testprovider.DataSourceType{ + DataSource: &testprovider.DataSourceWithConfigValidatorsAndGetSchemaAndMetadata{ GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return testSchema, nil }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSourceWithConfigValidators{ - DataSource: &testprovider.DataSource{}, - ConfigValidatorsMethod: func(ctx context.Context) []datasource.ConfigValidator { - return []datasource.ConfigValidator{ - &testprovider.DataSourceConfigValidator{ - ValidateDataSourceMethod: func(ctx context.Context, req datasource.ValidateConfigRequest, resp *datasource.ValidateConfigResponse) { - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, - } + DataSource: &testprovider.DataSource{}, + ConfigValidatorsMethod: func(ctx context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{ + &testprovider.DataSourceConfigValidator{ + ValidateDataSourceMethod: func(ctx context.Context, req datasource.ValidateConfigRequest, resp *datasource.ValidateConfigResponse) { + resp.Diagnostics.AddError("error summary", "error detail") + }, }, - }, nil + } }, }, }, @@ -234,27 +225,23 @@ func TestServerValidateDataSourceConfig(t *testing.T) { }, request: &fwserver.ValidateDataSourceConfigRequest{ Config: &testConfig, - DataSourceType: &testprovider.DataSourceType{ + DataSource: &testprovider.DataSourceWithGetSchemaAndMetadataAndValidateConfig{ GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return testSchema, nil }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSourceWithValidateConfig{ - DataSource: &testprovider.DataSource{}, - ValidateConfigMethod: func(ctx context.Context, req datasource.ValidateConfigRequest, resp *datasource.ValidateConfigResponse) { - var got types.String + DataSource: &testprovider.DataSource{}, + ValidateConfigMethod: func(ctx context.Context, req datasource.ValidateConfigRequest, resp *datasource.ValidateConfigResponse) { + var got types.String - resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("test"), &got)...) + resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("test"), &got)...) - if resp.Diagnostics.HasError() { - return - } + if resp.Diagnostics.HasError() { + return + } - if got.Value != "test-value" { - resp.Diagnostics.AddError("Incorrect req.Config", "expected test-value, got "+got.Value) - } - }, - }, nil + if got.Value != "test-value" { + resp.Diagnostics.AddError("Incorrect req.Config", "expected test-value, got "+got.Value) + } }, }, }, @@ -266,18 +253,14 @@ func TestServerValidateDataSourceConfig(t *testing.T) { }, request: &fwserver.ValidateDataSourceConfigRequest{ Config: &testConfig, - DataSourceType: &testprovider.DataSourceType{ + DataSource: &testprovider.DataSourceWithGetSchemaAndMetadataAndValidateConfig{ GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return testSchema, nil }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSourceWithValidateConfig{ - DataSource: &testprovider.DataSource{}, - ValidateConfigMethod: func(ctx context.Context, req datasource.ValidateConfigRequest, resp *datasource.ValidateConfigResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil + DataSource: &testprovider.DataSource{}, + ValidateConfigMethod: func(ctx context.Context, req datasource.ValidateConfigRequest, resp *datasource.ValidateConfigResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") }, }, }, diff --git a/internal/fwserver/server_validateresourceconfig.go b/internal/fwserver/server_validateresourceconfig.go index 6e14710c9..1c057f83a 100644 --- a/internal/fwserver/server_validateresourceconfig.go +++ b/internal/fwserver/server_validateresourceconfig.go @@ -5,7 +5,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/logging" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/tfsdk" ) @@ -13,8 +12,8 @@ import ( // ValidateResourceConfigRequest is the framework server request for the // ValidateResourceConfig RPC. type ValidateResourceConfigRequest struct { - Config *tfsdk.Config - ResourceType provider.ResourceType + Config *tfsdk.Config + Resource resource.Resource } // ValidateResourceConfigResponse is the framework server response for the @@ -29,22 +28,30 @@ func (s *Server) ValidateResourceConfig(ctx context.Context, req *ValidateResour return } - // Always instantiate new Resource instances. - logging.FrameworkDebug(ctx, "Calling provider defined ResourceType NewResource") - resourceImpl, diags := req.ResourceType.NewResource(ctx, s.Provider) - logging.FrameworkDebug(ctx, "Called provider defined ResourceType NewResource") + if _, ok := req.Resource.(resource.ResourceWithConfigure); ok { + logging.FrameworkTrace(ctx, "Resource implements ResourceWithConfigure") - resp.Diagnostics.Append(diags...) + configureReq := resource.ConfigureRequest{ + ProviderData: s.ResourceConfigureData, + } + configureResp := resource.ConfigureResponse{} - if resp.Diagnostics.HasError() { - return + logging.FrameworkDebug(ctx, "Calling provider defined Resource Configure") + req.Resource.(resource.ResourceWithConfigure).Configure(ctx, configureReq, &configureResp) + logging.FrameworkDebug(ctx, "Called provider defined Resource Configure") + + resp.Diagnostics.Append(configureResp.Diagnostics...) + + if resp.Diagnostics.HasError() { + return + } } vdscReq := resource.ValidateConfigRequest{ Config: *req.Config, } - if resourceWithConfigValidators, ok := resourceImpl.(resource.ResourceWithConfigValidators); ok { + if resourceWithConfigValidators, ok := req.Resource.(resource.ResourceWithConfigValidators); ok { logging.FrameworkTrace(ctx, "Resource implements ResourceWithConfigValidators") for _, configValidator := range resourceWithConfigValidators.ConfigValidators(ctx) { @@ -72,7 +79,7 @@ func (s *Server) ValidateResourceConfig(ctx context.Context, req *ValidateResour } } - if resourceWithValidateConfig, ok := resourceImpl.(resource.ResourceWithValidateConfig); ok { + if resourceWithValidateConfig, ok := req.Resource.(resource.ResourceWithValidateConfig); ok { logging.FrameworkTrace(ctx, "Resource implements ResourceWithValidateConfig") vdscResp := &resource.ValidateConfigResponse{ diff --git a/internal/fwserver/server_validateresourceconfig_test.go b/internal/fwserver/server_validateresourceconfig_test.go index e1503236d..1ab356023 100644 --- a/internal/fwserver/server_validateresourceconfig_test.go +++ b/internal/fwserver/server_validateresourceconfig_test.go @@ -9,7 +9,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" "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" @@ -112,7 +111,7 @@ func TestServerValidateResourceConfig(t *testing.T) { }, request: &fwserver.ValidateResourceConfigRequest{ Config: &testConfig, - ResourceType: &testprovider.ResourceType{ + Resource: &testprovider.ResourceWithGetSchema{ GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return testSchema, nil }, @@ -126,7 +125,7 @@ func TestServerValidateResourceConfig(t *testing.T) { }, request: &fwserver.ValidateResourceConfigRequest{ Config: &testConfigAttributeValidator, - ResourceType: &testprovider.ResourceType{ + Resource: &testprovider.ResourceWithGetSchema{ GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return testSchemaAttributeValidator, nil }, @@ -140,7 +139,7 @@ func TestServerValidateResourceConfig(t *testing.T) { }, request: &fwserver.ValidateResourceConfigRequest{ Config: &testConfigAttributeValidatorError, - ResourceType: &testprovider.ResourceType{ + Resource: &testprovider.ResourceWithGetSchema{ GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return testSchemaAttributeValidatorError, nil }, @@ -162,33 +161,29 @@ func TestServerValidateResourceConfig(t *testing.T) { }, request: &fwserver.ValidateResourceConfigRequest{ Config: &testConfig, - ResourceType: &testprovider.ResourceType{ + Resource: &testprovider.ResourceWithConfigValidatorsAndGetSchemaAndMetadata{ GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return testSchema, nil }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithConfigValidators{ - Resource: &testprovider.Resource{}, - ConfigValidatorsMethod: func(ctx context.Context) []resource.ConfigValidator { - return []resource.ConfigValidator{ - &testprovider.ResourceConfigValidator{ - ValidateResourceMethod: func(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { - var got types.String + Resource: &testprovider.Resource{}, + ConfigValidatorsMethod: func(ctx context.Context) []resource.ConfigValidator { + return []resource.ConfigValidator{ + &testprovider.ResourceConfigValidator{ + ValidateResourceMethod: func(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { + var got types.String - resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("test"), &got)...) + resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("test"), &got)...) - if resp.Diagnostics.HasError() { - return - } + if resp.Diagnostics.HasError() { + return + } - if got.Value != "test-value" { - resp.Diagnostics.AddError("Incorrect req.Config", "expected test-value, got "+got.Value) - } - }, - }, - } + if got.Value != "test-value" { + resp.Diagnostics.AddError("Incorrect req.Config", "expected test-value, got "+got.Value) + } + }, }, - }, nil + } }, }, }, @@ -200,23 +195,19 @@ func TestServerValidateResourceConfig(t *testing.T) { }, request: &fwserver.ValidateResourceConfigRequest{ Config: &testConfig, - ResourceType: &testprovider.ResourceType{ + Resource: &testprovider.ResourceWithConfigValidatorsAndGetSchemaAndMetadata{ GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return testSchema, nil }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithConfigValidators{ - Resource: &testprovider.Resource{}, - ConfigValidatorsMethod: func(ctx context.Context) []resource.ConfigValidator { - return []resource.ConfigValidator{ - &testprovider.ResourceConfigValidator{ - ValidateResourceMethod: func(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, - } + Resource: &testprovider.Resource{}, + ConfigValidatorsMethod: func(ctx context.Context) []resource.ConfigValidator { + return []resource.ConfigValidator{ + &testprovider.ResourceConfigValidator{ + ValidateResourceMethod: func(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { + resp.Diagnostics.AddError("error summary", "error detail") + }, }, - }, nil + } }, }, }, @@ -234,27 +225,23 @@ func TestServerValidateResourceConfig(t *testing.T) { }, request: &fwserver.ValidateResourceConfigRequest{ Config: &testConfig, - ResourceType: &testprovider.ResourceType{ + Resource: &testprovider.ResourceWithGetSchemaAndMetadataAndValidateConfig{ GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return testSchema, nil }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithValidateConfig{ - Resource: &testprovider.Resource{}, - ValidateConfigMethod: func(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { - var got types.String + Resource: &testprovider.Resource{}, + ValidateConfigMethod: func(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { + var got types.String - resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("test"), &got)...) + resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("test"), &got)...) - if resp.Diagnostics.HasError() { - return - } + if resp.Diagnostics.HasError() { + return + } - if got.Value != "test-value" { - resp.Diagnostics.AddError("Incorrect req.Config", "expected test-value, got "+got.Value) - } - }, - }, nil + if got.Value != "test-value" { + resp.Diagnostics.AddError("Incorrect req.Config", "expected test-value, got "+got.Value) + } }, }, }, @@ -266,18 +253,14 @@ func TestServerValidateResourceConfig(t *testing.T) { }, request: &fwserver.ValidateResourceConfigRequest{ Config: &testConfig, - ResourceType: &testprovider.ResourceType{ + Resource: &testprovider.ResourceWithGetSchemaAndMetadataAndValidateConfig{ GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return testSchema, nil }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithValidateConfig{ - Resource: &testprovider.Resource{}, - ValidateConfigMethod: func(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil + Resource: &testprovider.Resource{}, + ValidateConfigMethod: func(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") }, }, }, diff --git a/internal/proto5server/server_applyresourcechange.go b/internal/proto5server/server_applyresourcechange.go index 97acd3c85..7dfe24d84 100644 --- a/internal/proto5server/server_applyresourcechange.go +++ b/internal/proto5server/server_applyresourcechange.go @@ -17,7 +17,7 @@ func (s *Server) ApplyResourceChange(ctx context.Context, proto5Req *tfprotov5.A fwResp := &fwserver.ApplyResourceChangeResponse{} - resourceType, diags := s.FrameworkServer.ResourceType(ctx, proto5Req.TypeName) + resource, diags := s.FrameworkServer.Resource(ctx, proto5Req.TypeName) fwResp.Diagnostics.Append(diags...) @@ -41,7 +41,7 @@ func (s *Server) ApplyResourceChange(ctx context.Context, proto5Req *tfprotov5.A return toproto5.ApplyResourceChangeResponse(ctx, fwResp), nil } - fwReq, diags := fromproto5.ApplyResourceChangeRequest(ctx, proto5Req, resourceType, resourceSchema, providerMetaSchema) + fwReq, diags := fromproto5.ApplyResourceChangeRequest(ctx, proto5Req, resource, resourceSchema, providerMetaSchema) fwResp.Diagnostics.Append(diags...) diff --git a/internal/proto5server/server_applyresourcechange_test.go b/internal/proto5server/server_applyresourcechange_test.go index c91b0cb7b..f3a2bf7b1 100644 --- a/internal/proto5server/server_applyresourcechange_test.go +++ b/internal/proto5server/server_applyresourcechange_test.go @@ -13,7 +13,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" - "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" @@ -82,14 +81,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var data testSchemaData @@ -108,10 +110,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -139,14 +141,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var data testSchemaData @@ -165,10 +170,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -197,14 +202,17 @@ func TestServerApplyResourceChange(t *testing.T) { FrameworkServer: fwserver.Server{ Provider: &testprovider.ProviderWithMetaSchema{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var metadata testProviderMetaData @@ -226,10 +234,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, GetMetaSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { @@ -262,14 +270,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddWarning("warning summary", "warning detail") resp.Diagnostics.AddError("error summary", "error detail") @@ -280,10 +291,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -320,14 +331,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var data testSchemaData @@ -340,10 +354,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -371,14 +385,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // Intentionally missing resp.State.Set() }, @@ -388,10 +405,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -426,14 +443,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var data testSchemaData @@ -450,10 +470,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -475,14 +495,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") }, @@ -498,10 +521,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -523,14 +546,17 @@ func TestServerApplyResourceChange(t *testing.T) { FrameworkServer: fwserver.Server{ Provider: &testprovider.ProviderWithMetaSchema{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") }, @@ -546,10 +572,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, GetMetaSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { @@ -575,14 +601,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") }, @@ -602,10 +631,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -628,14 +657,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") }, @@ -646,10 +678,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -685,14 +717,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") }, @@ -702,10 +737,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -726,14 +761,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") @@ -750,10 +788,10 @@ func TestServerApplyResourceChange(t *testing.T) { resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -785,14 +823,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") @@ -809,10 +850,10 @@ func TestServerApplyResourceChange(t *testing.T) { resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestComputed.Value) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -844,14 +885,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") }, @@ -867,10 +911,10 @@ func TestServerApplyResourceChange(t *testing.T) { resp.Diagnostics.AddError("Unexpected req.State Value", "Got: "+data.TestRequired.Value) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -903,14 +947,17 @@ func TestServerApplyResourceChange(t *testing.T) { FrameworkServer: fwserver.Server{ Provider: &testprovider.ProviderWithMetaSchema{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") }, @@ -926,10 +973,10 @@ func TestServerApplyResourceChange(t *testing.T) { resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, GetMetaSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { @@ -967,14 +1014,17 @@ func TestServerApplyResourceChange(t *testing.T) { FrameworkServer: fwserver.Server{ Provider: &testprovider.ProviderWithMetaSchema{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") }, @@ -994,10 +1044,10 @@ func TestServerApplyResourceChange(t *testing.T) { ) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, GetMetaSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { @@ -1038,14 +1088,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") }, @@ -1056,10 +1109,10 @@ func TestServerApplyResourceChange(t *testing.T) { resp.Diagnostics.AddWarning("warning summary", "warning detail") resp.Diagnostics.AddError("error summary", "error detail") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -1102,14 +1155,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") }, @@ -1122,10 +1178,10 @@ func TestServerApplyResourceChange(t *testing.T) { resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -1156,14 +1212,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") }, @@ -1173,10 +1232,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { resp.State.RemoveResource(ctx) }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -1212,14 +1271,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") }, @@ -1231,10 +1293,10 @@ func TestServerApplyResourceChange(t *testing.T) { resp.Diagnostics.Append(diags...) }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, diff --git a/internal/proto5server/server_getproviderschema_test.go b/internal/proto5server/server_getproviderschema_test.go index 0bf0de5f7..cfd8c72c5 100644 --- a/internal/proto5server/server_getproviderschema_test.go +++ b/internal/proto5server/server_getproviderschema_test.go @@ -6,11 +6,13 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" "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" "github.com/hashicorp/terraform-plugin-go/tfprotov5" @@ -27,10 +29,278 @@ func TestServerGetProviderSchema(t *testing.T) { expectedError error expectedResponse *tfprotov5.GetProviderSchemaResponse }{ - "datasourceschemas": { + "datasourceschemas-DataSources": { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source1" + }, + } + }, + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test2": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source2" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov5.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov5.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov5.Schema{ + "test_data_source1": { + Block: &tfprotov5.SchemaBlock{ + Attributes: []*tfprotov5.SchemaAttribute{ + { + Name: "test1", + Required: true, + Type: tftypes.String, + }, + }, + }, + }, + "test_data_source2": { + Block: &tfprotov5.SchemaBlock{ + Attributes: []*tfprotov5.SchemaAttribute{ + { + Name: "test2", + Required: true, + Type: tftypes.String, + }, + }, + }, + }, + }, + Provider: &tfprotov5.Schema{ + Block: &tfprotov5.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov5.Schema{}, + ServerCapabilities: &tfprotov5.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "datasourceschemas-DataSources-duplicate-type-name": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + } + }, + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test2": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov5.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov5.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov5.Schema{}, + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "Duplicate Data Source Type Defined", + Detail: "The test_data_source data source type name was returned for multiple data sources. " + + "Data source type names must be unique. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + Provider: &tfprotov5.Schema{ + Block: &tfprotov5.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov5.Schema{}, + ServerCapabilities: &tfprotov5.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "datasourceschemas-DataSources-empty-type-name": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithMetadata{ + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov5.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov5.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov5.Schema{}, + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "Data Source Type Name Missing", + Detail: "The *testprovider.DataSourceWithMetadata DataSource returned an empty string from the Metadata method. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + Provider: &tfprotov5.Schema{ + Block: &tfprotov5.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov5.Schema{}, + ServerCapabilities: &tfprotov5.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "datasourceschemas-DataSources-missing-schema": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithMetadata{ + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov5.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov5.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov5.Schema{}, + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "Data Source Schema Missing", + Detail: "The *testprovider.DataSourceWithMetadata DataSource in the provider is missing the GetSchema method. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + Provider: &tfprotov5.Schema{ + Block: &tfprotov5.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov5.Schema{}, + ServerCapabilities: &tfprotov5.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "datasourceschemas-DataSources-missing-type-name": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchema{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov5.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov5.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov5.Schema{}, + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "Data Source Type Name Missing", + Detail: "The *testprovider.DataSourceWithGetSchema DataSource in the provider DataSources method results is missing the Metadata method. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + Provider: &tfprotov5.Schema{ + Block: &tfprotov5.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov5.Schema{}, + ServerCapabilities: &tfprotov5.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "datasourceschemas-GetDataSources": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.ProviderWithGetDataSources{ + //nolint:staticcheck // Internal implementation GetDataSourcesMethod: func(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { return map[string]provider.DataSourceType{ "test_data_source1": &testprovider.DataSourceType{ @@ -175,10 +445,278 @@ func TestServerGetProviderSchema(t *testing.T) { }, }, }, - "resourceschemas": { + "resourceschemas-Resources": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource1" + }, + } + }, + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test2": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource2" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov5.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov5.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov5.Schema{}, + Provider: &tfprotov5.Schema{ + Block: &tfprotov5.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov5.Schema{ + "test_resource1": { + Block: &tfprotov5.SchemaBlock{ + Attributes: []*tfprotov5.SchemaAttribute{ + { + Name: "test1", + Required: true, + Type: tftypes.String, + }, + }, + }, + }, + "test_resource2": { + Block: &tfprotov5.SchemaBlock{ + Attributes: []*tfprotov5.SchemaAttribute{ + { + Name: "test2", + Required: true, + Type: tftypes.String, + }, + }, + }, + }, + }, + ServerCapabilities: &tfprotov5.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "resourceschemas-Resources-duplicate-type-name": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + } + }, + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test2": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov5.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov5.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov5.Schema{}, + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "Duplicate Resource Type Defined", + Detail: "The test_resource resource type name was returned for multiple resources. " + + "Resource type names must be unique. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + Provider: &tfprotov5.Schema{ + Block: &tfprotov5.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov5.Schema{}, + ServerCapabilities: &tfprotov5.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "resourceschemas-Resources-empty-type-name": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithMetadata{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov5.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov5.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov5.Schema{}, + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "Resource Type Name Missing", + Detail: "The *testprovider.ResourceWithMetadata Resource returned an empty string from the Metadata method. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + Provider: &tfprotov5.Schema{ + Block: &tfprotov5.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov5.Schema{}, + ServerCapabilities: &tfprotov5.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "resourceschemas-Resources-missing-schema": { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithMetadata{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov5.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov5.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov5.Schema{}, + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "Resource Schema Missing", + Detail: "The *testprovider.ResourceWithMetadata Resource in the provider is missing the GetSchema method. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + Provider: &tfprotov5.Schema{ + Block: &tfprotov5.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov5.Schema{}, + ServerCapabilities: &tfprotov5.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "resourceschemas-Resources-missing-type-name": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchema{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov5.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov5.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov5.Schema{}, + Diagnostics: []*tfprotov5.Diagnostic{ + { + Severity: tfprotov5.DiagnosticSeverityError, + Summary: "Resource Type Name Missing", + Detail: "The *testprovider.ResourceWithGetSchema Resource in the provider Resources method results is missing the Metadata method. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + Provider: &tfprotov5.Schema{ + Block: &tfprotov5.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov5.Schema{}, + ServerCapabilities: &tfprotov5.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "resourceschemas-GetResources": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.ProviderWithGetResources{ + //nolint:staticcheck // Internal implementation GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { return map[string]provider.ResourceType{ "test_resource1": &testprovider.ResourceType{ @@ -320,12 +858,17 @@ func TestServerGetProviderSchema_logging(t *testing.T) { }, { "@level": "debug", - "@message": "Calling provider defined Provider GetResources", + "@message": "Calling provider defined Provider Resources", "@module": "sdk.framework", }, { "@level": "debug", - "@message": "Called provider defined Provider GetResources", + "@message": "Called provider defined Provider Resources", + "@module": "sdk.framework", + }, + { + "@level": "trace", + "@message": "Checking ResourceTypes lock", "@module": "sdk.framework", }, { @@ -340,12 +883,17 @@ func TestServerGetProviderSchema_logging(t *testing.T) { }, { "@level": "debug", - "@message": "Calling provider defined Provider GetDataSources", + "@message": "Calling provider defined Provider DataSources", "@module": "sdk.framework", }, { "@level": "debug", - "@message": "Called provider defined Provider GetDataSources", + "@message": "Called provider defined Provider DataSources", + "@module": "sdk.framework", + }, + { + "@level": "trace", + "@message": "Checking DataSourceTypes lock", "@module": "sdk.framework", }, } diff --git a/internal/proto5server/server_importresourcestate.go b/internal/proto5server/server_importresourcestate.go index dab3e2507..76cf7de43 100644 --- a/internal/proto5server/server_importresourcestate.go +++ b/internal/proto5server/server_importresourcestate.go @@ -17,7 +17,7 @@ func (s *Server) ImportResourceState(ctx context.Context, proto5Req *tfprotov5.I fwResp := &fwserver.ImportResourceStateResponse{} - resourceType, diags := s.FrameworkServer.ResourceType(ctx, proto5Req.TypeName) + resource, diags := s.FrameworkServer.Resource(ctx, proto5Req.TypeName) fwResp.Diagnostics.Append(diags...) @@ -33,7 +33,7 @@ func (s *Server) ImportResourceState(ctx context.Context, proto5Req *tfprotov5.I return toproto5.ImportResourceStateResponse(ctx, fwResp), nil } - fwReq, diags := fromproto5.ImportResourceStateRequest(ctx, proto5Req, resourceType, resourceSchema) + fwReq, diags := fromproto5.ImportResourceStateRequest(ctx, proto5Req, resource, resourceSchema) fwResp.Diagnostics.Append(diags...) diff --git a/internal/proto5server/server_importresourcestate_test.go b/internal/proto5server/server_importresourcestate_test.go index 454f1d39d..63204f87c 100644 --- a/internal/proto5server/server_importresourcestate_test.go +++ b/internal/proto5server/server_importresourcestate_test.go @@ -13,7 +13,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" "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" @@ -63,26 +62,27 @@ func TestServerImportResourceState(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithImportState{ - Resource: &testprovider.Resource{}, - ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { - if req.ID != "test-id" { - resp.Diagnostics.AddError("unexpected req.ID value: %s", req.ID) - } - - resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndImportStateAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + if req.ID != "test-id" { + resp.Diagnostics.AddError("unexpected req.ID value: %s", req.ID) + } + + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) + }, + } }, - }, nil + } }, }, }, @@ -104,23 +104,24 @@ func TestServerImportResourceState(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithImportState{ - Resource: &testprovider.Resource{}, - ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndImportStateAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") + }, + } }, - }, nil + } }, }, }, @@ -148,22 +149,23 @@ func TestServerImportResourceState(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithImportState{ - Resource: &testprovider.Resource{}, - ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { - resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndImportStateAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) + }, + } }, - }, nil + } }, }, }, @@ -185,26 +187,27 @@ func TestServerImportResourceState(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithImportState{ - Resource: &testprovider.Resource{}, - ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { - diags := resp.Private.SetKey(ctx, "providerKey", []byte(`{"key": "value"}`)) - - resp.Diagnostics.Append(diags...) - - resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndImportStateAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + diags := resp.Private.SetKey(ctx, "providerKey", []byte(`{"key": "value"}`)) + + resp.Diagnostics.Append(diags...) + + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) + }, + } }, - }, nil + } }, }, }, diff --git a/internal/proto5server/server_planresourcechange.go b/internal/proto5server/server_planresourcechange.go index ccdda4aa4..60e71c445 100644 --- a/internal/proto5server/server_planresourcechange.go +++ b/internal/proto5server/server_planresourcechange.go @@ -17,7 +17,7 @@ func (s *Server) PlanResourceChange(ctx context.Context, proto5Req *tfprotov5.Pl fwResp := &fwserver.PlanResourceChangeResponse{} - resourceType, diags := s.FrameworkServer.ResourceType(ctx, proto5Req.TypeName) + resource, diags := s.FrameworkServer.Resource(ctx, proto5Req.TypeName) fwResp.Diagnostics.Append(diags...) @@ -41,7 +41,7 @@ func (s *Server) PlanResourceChange(ctx context.Context, proto5Req *tfprotov5.Pl return toproto5.PlanResourceChangeResponse(ctx, fwResp), nil } - fwReq, diags := fromproto5.PlanResourceChangeRequest(ctx, proto5Req, resourceType, resourceSchema, providerMetaSchema) + fwReq, diags := fromproto5.PlanResourceChangeRequest(ctx, proto5Req, resource, resourceSchema, providerMetaSchema) fwResp.Diagnostics.Append(diags...) diff --git a/internal/proto5server/server_planresourcechange_test.go b/internal/proto5server/server_planresourcechange_test.go index 18b0f3c74..29f7e88b1 100644 --- a/internal/proto5server/server_planresourcechange_test.go +++ b/internal/proto5server/server_planresourcechange_test.go @@ -9,7 +9,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" "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" @@ -80,27 +79,28 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - if data.TestRequired.Value != "test-config-value" { - resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) - } - }, - }, nil - }, + if data.TestRequired.Value != "test-config-value" { + resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) + } + }, + } }, - }, nil + } }, }, }, @@ -128,27 +128,28 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - if !data.TestComputed.Unknown { - resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestComputed.Value) - } - }, - }, nil - }, + if !data.TestComputed.Unknown { + resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestComputed.Value) + } + }, + } }, - }, nil + } }, }, }, @@ -177,27 +178,28 @@ func TestServerPlanResourceChange(t *testing.T) { FrameworkServer: fwserver.Server{ Provider: &testprovider.ProviderWithMetaSchema{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testProviderMetaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testProviderMetaData - resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) + resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) - if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { - resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) - } - }, - }, nil - }, + if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { + resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) + } + }, + } }, - }, nil + } }, }, GetMetaSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { @@ -230,22 +232,23 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") + }, + } }, - }, nil + } }, }, }, @@ -285,27 +288,28 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - data.TestComputed = types.String{Value: "test-plannedstate-value"} + data.TestComputed = types.String{Value: "test-plannedstate-value"} - resp.Diagnostics.Append(resp.Plan.Set(ctx, &data)...) - }, - }, nil - }, + resp.Diagnostics.Append(resp.Plan.Set(ctx, &data)...) + }, + } }, - }, nil + } }, }, }, @@ -333,29 +337,30 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - // This is a strange thing to signal on creation, - // but the framework does not prevent you from - // doing it and it might be overly burdensome on - // provider developers to have the framework raise - // an error if it is technically valid in the - // protocol. - resp.RequiresReplace = path.Paths{ - path.Root("test_required"), - } - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + // This is a strange thing to signal on creation, + // but the framework does not prevent you from + // doing it and it might be overly burdensome on + // provider developers to have the framework raise + // an error if it is technically valid in the + // protocol. + resp.RequiresReplace = path.Paths{ + path.Root("test_required"), + } + }, + } }, - }, nil + } }, }, }, @@ -386,27 +391,28 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) - if data.TestRequired.Value != "test-priorstate-value" { - resp.Diagnostics.AddError("Unexpected req.State Value", "Got: "+data.TestRequired.Value) - } - }, - }, nil - }, + if data.TestRequired.Value != "test-priorstate-value" { + resp.Diagnostics.AddError("Unexpected req.State Value", "Got: "+data.TestRequired.Value) + } + }, + } }, - }, nil + } }, }, }, @@ -428,27 +434,28 @@ func TestServerPlanResourceChange(t *testing.T) { FrameworkServer: fwserver.Server{ Provider: &testprovider.ProviderWithMetaSchema{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testProviderMetaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testProviderMetaData - resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) + resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) - if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { - resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) - } - }, - }, nil - }, + if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { + resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) + } + }, + } }, - }, nil + } }, }, GetMetaSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { @@ -474,22 +481,23 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") + }, + } }, - }, nil + } }, }, }, @@ -522,22 +530,23 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - // This is invalid logic to run during deletion. - resp.Diagnostics.Append(resp.Plan.SetAttribute(ctx, path.Root("test_computed"), types.String{Value: "test-plannedstate-value"})...) - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + // This is invalid logic to run during deletion. + resp.Diagnostics.Append(resp.Plan.SetAttribute(ctx, path.Root("test_computed"), types.String{Value: "test-plannedstate-value"})...) + }, + } }, - }, nil + } }, }, }, @@ -570,29 +579,30 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - // This is a strange thing to signal on destroy, - // but the framework does not prevent you from - // doing it and it might be overly burdensome on - // provider developers to have the framework raise - // an error if it is technically valid in the - // protocol. - resp.RequiresReplace = path.Paths{ - path.Root("test_required"), - } - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + // This is a strange thing to signal on destroy, + // but the framework does not prevent you from + // doing it and it might be overly burdensome on + // provider developers to have the framework raise + // an error if it is technically valid in the + // protocol. + resp.RequiresReplace = path.Paths{ + path.Root("test_required"), + } + }, + } }, - }, nil + } }, }, }, @@ -616,27 +626,28 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - if data.TestRequired.Value != "test-new-value" { - resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) - } - }, - }, nil - }, + if data.TestRequired.Value != "test-new-value" { + resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) + } + }, + } }, - }, nil + } }, }, }, @@ -667,27 +678,28 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - if !data.TestComputed.Unknown { - resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestComputed.Value) - } - }, - }, nil - }, + if !data.TestComputed.Unknown { + resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestComputed.Value) + } + }, + } }, - }, nil + } }, }, }, @@ -718,27 +730,28 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) - if data.TestRequired.Value != "test-old-value" { - resp.Diagnostics.AddError("Unexpected req.State Value", "Got: "+data.TestRequired.Value) - } - }, - }, nil - }, + if data.TestRequired.Value != "test-old-value" { + resp.Diagnostics.AddError("Unexpected req.State Value", "Got: "+data.TestRequired.Value) + } + }, + } }, - }, nil + } }, }, }, @@ -770,27 +783,28 @@ func TestServerPlanResourceChange(t *testing.T) { FrameworkServer: fwserver.Server{ Provider: &testprovider.ProviderWithMetaSchema{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testProviderMetaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testProviderMetaData - resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) + resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) - if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { - resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) - } - }, - }, nil - }, + if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { + resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) + } + }, + } }, - }, nil + } }, }, GetMetaSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { @@ -826,22 +840,23 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") + }, + } }, - }, nil + } }, }, }, @@ -884,27 +899,28 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - data.TestComputed = types.String{Value: "test-plannedstate-value"} + data.TestComputed = types.String{Value: "test-plannedstate-value"} - resp.Diagnostics.Append(resp.Plan.Set(ctx, &data)...) - }, - }, nil - }, + resp.Diagnostics.Append(resp.Plan.Set(ctx, &data)...) + }, + } }, - }, nil + } }, }, }, @@ -935,23 +951,24 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - resp.RequiresReplace = path.Paths{ - path.Root("test_required"), - } - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + resp.RequiresReplace = path.Paths{ + path.Root("test_required"), + } + }, + } }, - }, nil + } }, }, }, diff --git a/internal/proto5server/server_readdatasource.go b/internal/proto5server/server_readdatasource.go index c94987652..22d1bff33 100644 --- a/internal/proto5server/server_readdatasource.go +++ b/internal/proto5server/server_readdatasource.go @@ -17,7 +17,7 @@ func (s *Server) ReadDataSource(ctx context.Context, proto5Req *tfprotov5.ReadDa fwResp := &fwserver.ReadDataSourceResponse{} - dataSourceType, diags := s.FrameworkServer.DataSourceType(ctx, proto5Req.TypeName) + dataSource, diags := s.FrameworkServer.DataSource(ctx, proto5Req.TypeName) fwResp.Diagnostics.Append(diags...) @@ -41,7 +41,7 @@ func (s *Server) ReadDataSource(ctx context.Context, proto5Req *tfprotov5.ReadDa return toproto5.ReadDataSourceResponse(ctx, fwResp), nil } - fwReq, diags := fromproto5.ReadDataSourceRequest(ctx, proto5Req, dataSourceType, dataSourceSchema, providerMetaSchema) + fwReq, diags := fromproto5.ReadDataSourceRequest(ctx, proto5Req, dataSource, dataSourceSchema, providerMetaSchema) fwResp.Diagnostics.Append(diags...) diff --git a/internal/proto5server/server_readdatasource_test.go b/internal/proto5server/server_readdatasource_test.go index ec1523e17..ff3a46158 100644 --- a/internal/proto5server/server_readdatasource_test.go +++ b/internal/proto5server/server_readdatasource_test.go @@ -9,7 +9,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" - "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-go/tfprotov5" @@ -61,17 +60,20 @@ func TestServerReadDataSource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetDataSourcesMethod: func(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { - return map[string]provider.DataSourceType{ - "test_data_source": &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return tfsdk.Schema{}, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSource{}, nil - }, + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{}, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + DataSource: &testprovider.DataSource{}, + } }, - }, nil + } }, }, }, @@ -88,14 +90,17 @@ func TestServerReadDataSource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetDataSourcesMethod: func(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { - return map[string]provider.DataSourceType{ - "test_data_source": &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSource{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + DataSource: &testprovider.DataSource{ ReadMethod: func(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { var config struct { TestComputed types.String `tfsdk:"test_computed"` @@ -108,10 +113,10 @@ func TestServerReadDataSource(t *testing.T) { resp.Diagnostics.AddError("unexpected req.Config value: %s", config.TestRequired.Value) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -129,14 +134,17 @@ func TestServerReadDataSource(t *testing.T) { FrameworkServer: fwserver.Server{ Provider: &testprovider.ProviderWithMetaSchema{ Provider: &testprovider.Provider{ - GetDataSourcesMethod: func(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { - return map[string]provider.DataSourceType{ - "test_data_source": &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return tfsdk.Schema{}, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSource{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{}, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + DataSource: &testprovider.DataSource{ ReadMethod: func(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { var config struct { TestComputed types.String `tfsdk:"test_computed"` @@ -149,10 +157,10 @@ func TestServerReadDataSource(t *testing.T) { resp.Diagnostics.AddError("unexpected req.ProviderMeta value: %s", config.TestRequired.Value) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, GetMetaSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { @@ -174,22 +182,25 @@ func TestServerReadDataSource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetDataSourcesMethod: func(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { - return map[string]provider.DataSourceType{ - "test_data_source": &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSource{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + DataSource: &testprovider.DataSource{ ReadMethod: func(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { resp.Diagnostics.AddWarning("warning summary", "warning detail") resp.Diagnostics.AddError("error summary", "error detail") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -218,14 +229,17 @@ func TestServerReadDataSource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetDataSourcesMethod: func(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { - return map[string]provider.DataSourceType{ - "test_data_source": &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSource{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + DataSource: &testprovider.DataSource{ ReadMethod: func(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { var data struct { TestComputed types.String `tfsdk:"test_computed"` @@ -238,10 +252,10 @@ func TestServerReadDataSource(t *testing.T) { resp.Diagnostics.Append(resp.State.Set(ctx, data)...) }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, diff --git a/internal/proto5server/server_readresource.go b/internal/proto5server/server_readresource.go index fb9b45b87..73c1b0f1f 100644 --- a/internal/proto5server/server_readresource.go +++ b/internal/proto5server/server_readresource.go @@ -18,7 +18,7 @@ func (s *Server) ReadResource(ctx context.Context, proto5Req *tfprotov5.ReadReso fwResp := &fwserver.ReadResourceResponse{} - resourceType, diags := s.FrameworkServer.ResourceType(ctx, proto5Req.TypeName) + resource, diags := s.FrameworkServer.Resource(ctx, proto5Req.TypeName) fwResp.Diagnostics.Append(diags...) @@ -42,7 +42,7 @@ func (s *Server) ReadResource(ctx context.Context, proto5Req *tfprotov5.ReadReso return toproto5.ReadResourceResponse(ctx, fwResp), nil } - fwReq, diags := fromproto5.ReadResourceRequest(ctx, proto5Req, resourceType, resourceSchema, providerMetaSchema) + fwReq, diags := fromproto5.ReadResourceRequest(ctx, proto5Req, resource, resourceSchema, providerMetaSchema) fwResp.Diagnostics.Append(diags...) diff --git a/internal/proto5server/server_readresource_test.go b/internal/proto5server/server_readresource_test.go index fdda2072a..15c932e13 100644 --- a/internal/proto5server/server_readresource_test.go +++ b/internal/proto5server/server_readresource_test.go @@ -13,7 +13,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" - "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" @@ -66,17 +65,20 @@ func TestServerReadResource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return tfsdk.Schema{}, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{}, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + } }, - }, nil + } }, }, }, @@ -93,14 +95,17 @@ func TestServerReadResource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var data struct { TestComputed types.String `tfsdk:"test_computed"` @@ -113,10 +118,10 @@ func TestServerReadResource(t *testing.T) { resp.Diagnostics.AddError("unexpected req.State value: %s", data.TestRequired.Value) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -134,14 +139,17 @@ func TestServerReadResource(t *testing.T) { FrameworkServer: fwserver.Server{ Provider: &testprovider.ProviderWithMetaSchema{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return tfsdk.Schema{}, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{}, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var data struct { TestComputed types.String `tfsdk:"test_computed"` @@ -154,10 +162,10 @@ func TestServerReadResource(t *testing.T) { resp.Diagnostics.AddError("unexpected req.ProviderMeta value: %s", data.TestRequired.Value) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, GetMetaSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { @@ -179,14 +187,17 @@ func TestServerReadResource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return tfsdk.Schema{}, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{}, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` got, diags := req.Private.GetKey(ctx, "providerKey") @@ -200,10 +211,10 @@ func TestServerReadResource(t *testing.T) { ) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -228,22 +239,25 @@ func TestServerReadResource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { resp.Diagnostics.AddWarning("warning summary", "warning detail") resp.Diagnostics.AddError("error summary", "error detail") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -272,14 +286,17 @@ func TestServerReadResource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var data struct { TestComputed types.String `tfsdk:"test_computed"` @@ -292,10 +309,10 @@ func TestServerReadResource(t *testing.T) { resp.Diagnostics.Append(resp.State.Set(ctx, data)...) }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -312,21 +329,24 @@ func TestServerReadResource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { resp.State.RemoveResource(ctx) }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -343,23 +363,26 @@ func TestServerReadResource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return tfsdk.Schema{}, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{}, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { diags := resp.Private.SetKey(ctx, "providerKey", []byte(`{"key": "value"}`)) resp.Diagnostics.Append(diags...) }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, diff --git a/internal/proto5server/server_upgraderesourcestate.go b/internal/proto5server/server_upgraderesourcestate.go index bb6aab956..f998e74cf 100644 --- a/internal/proto5server/server_upgraderesourcestate.go +++ b/internal/proto5server/server_upgraderesourcestate.go @@ -21,7 +21,7 @@ func (s *Server) UpgradeResourceState(ctx context.Context, proto5Req *tfprotov5. return toproto5.UpgradeResourceStateResponse(ctx, fwResp), nil } - resourceType, diags := s.FrameworkServer.ResourceType(ctx, proto5Req.TypeName) + resource, diags := s.FrameworkServer.Resource(ctx, proto5Req.TypeName) fwResp.Diagnostics.Append(diags...) @@ -37,7 +37,7 @@ func (s *Server) UpgradeResourceState(ctx context.Context, proto5Req *tfprotov5. return toproto5.UpgradeResourceStateResponse(ctx, fwResp), nil } - fwReq, diags := fromproto5.UpgradeResourceStateRequest(ctx, proto5Req, resourceType, resourceSchema) + fwReq, diags := fromproto5.UpgradeResourceStateRequest(ctx, proto5Req, resource, resourceSchema) fwResp.Diagnostics.Append(diags...) diff --git a/internal/proto5server/server_upgraderesourcestate_test.go b/internal/proto5server/server_upgraderesourcestate_test.go index 905717aa0..ea61a4ba0 100644 --- a/internal/proto5server/server_upgraderesourcestate_test.go +++ b/internal/proto5server/server_upgraderesourcestate_test.go @@ -8,7 +8,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" - "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" @@ -58,45 +57,46 @@ func TestServerUpgradeResourceState(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithUpgradeState{ - Resource: &testprovider.Resource{}, - UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { - return map[int64]resource.StateUpgrader{ - 0: { - StateUpgrader: func(_ context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { - expectedRawState := testNewTfprotov6RawState(t, map[string]interface{}{ - "id": "test-id-value", - "required_attribute": true, - }) + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadataAndUpgradeState{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return schema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{ + 0: { + StateUpgrader: func(_ context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { + expectedRawState := testNewTfprotov6RawState(t, map[string]interface{}{ + "id": "test-id-value", + "required_attribute": true, + }) - if diff := cmp.Diff(req.RawState, expectedRawState); diff != "" { - resp.Diagnostics.AddError("Unexpected req.RawState difference", diff) - } + if diff := cmp.Diff(req.RawState, expectedRawState); diff != "" { + resp.Diagnostics.AddError("Unexpected req.RawState difference", diff) + } - // Prevent Missing Upgraded Resource State error - resp.State = tfsdk.State{ - Raw: tftypes.NewValue(schemaType, map[string]tftypes.Value{ - "id": tftypes.NewValue(tftypes.String, "test-id-value"), - "optional_attribute": tftypes.NewValue(tftypes.String, nil), - "required_attribute": tftypes.NewValue(tftypes.String, "true"), - }), - Schema: schema, - } - }, + // Prevent Missing Upgraded Resource State error + resp.State = tfsdk.State{ + Raw: tftypes.NewValue(schemaType, map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "test-id-value"), + "optional_attribute": tftypes.NewValue(tftypes.String, nil), + "required_attribute": tftypes.NewValue(tftypes.String, "true"), + }), + Schema: schema, + } }, - } - }, - }, nil - }, + }, + } + }, + } }, - }, nil + } }, }, }, @@ -157,29 +157,30 @@ func TestServerUpgradeResourceState(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithUpgradeState{ - Resource: &testprovider.Resource{}, - UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { - return map[int64]resource.StateUpgrader{ - 0: { - StateUpgrader: func(_ context.Context, _ resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadataAndUpgradeState{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return schema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{ + 0: { + StateUpgrader: func(_ context.Context, _ resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") }, - } - }, - }, nil - }, + }, + } + }, + } }, - }, nil + } }, }, }, @@ -211,35 +212,36 @@ func TestServerUpgradeResourceState(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithUpgradeState{ - Resource: &testprovider.Resource{}, - UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { - return map[int64]resource.StateUpgrader{ - 0: { - StateUpgrader: func(_ context.Context, _ resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { - resp.State = tfsdk.State{ - Raw: tftypes.NewValue(schemaType, map[string]tftypes.Value{ - "id": tftypes.NewValue(tftypes.String, "test-id-value"), - "optional_attribute": tftypes.NewValue(tftypes.String, nil), - "required_attribute": tftypes.NewValue(tftypes.String, "true"), - }), - Schema: schema, - } - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadataAndUpgradeState{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return schema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{ + 0: { + StateUpgrader: func(_ context.Context, _ resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { + resp.State = tfsdk.State{ + Raw: tftypes.NewValue(schemaType, map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "test-id-value"), + "optional_attribute": tftypes.NewValue(tftypes.String, nil), + "required_attribute": tftypes.NewValue(tftypes.String, "true"), + }), + Schema: schema, + } }, - } - }, - }, nil - }, + }, + } + }, + } }, - }, nil + } }, }, }, diff --git a/internal/proto5server/server_validatedatasourceconfig.go b/internal/proto5server/server_validatedatasourceconfig.go index 3f83f9078..179503a10 100644 --- a/internal/proto5server/server_validatedatasourceconfig.go +++ b/internal/proto5server/server_validatedatasourceconfig.go @@ -17,7 +17,7 @@ func (s *Server) ValidateDataSourceConfig(ctx context.Context, proto5Req *tfprot fwResp := &fwserver.ValidateDataSourceConfigResponse{} - dataSourceType, diags := s.FrameworkServer.DataSourceType(ctx, proto5Req.TypeName) + dataSource, diags := s.FrameworkServer.DataSource(ctx, proto5Req.TypeName) fwResp.Diagnostics.Append(diags...) @@ -33,7 +33,7 @@ func (s *Server) ValidateDataSourceConfig(ctx context.Context, proto5Req *tfprot return toproto5.ValidateDataSourceConfigResponse(ctx, fwResp), nil } - fwReq, diags := fromproto5.ValidateDataSourceConfigRequest(ctx, proto5Req, dataSourceType, dataSourceSchema) + fwReq, diags := fromproto5.ValidateDataSourceConfigRequest(ctx, proto5Req, dataSource, dataSourceSchema) fwResp.Diagnostics.Append(diags...) diff --git a/internal/proto5server/server_validatedatasourceconfig_test.go b/internal/proto5server/server_validatedatasourceconfig_test.go index e27935369..e83d953af 100644 --- a/internal/proto5server/server_validatedatasourceconfig_test.go +++ b/internal/proto5server/server_validatedatasourceconfig_test.go @@ -9,7 +9,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" - "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-go/tfprotov5" @@ -54,17 +53,20 @@ func TestServerValidateDataSourceConfig(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetDataSourcesMethod: func(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { - return map[string]provider.DataSourceType{ - "test_data_source": &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return tfsdk.Schema{}, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSource{}, nil - }, + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{}, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + DataSource: &testprovider.DataSource{}, + } }, - }, nil + } }, }, }, @@ -78,17 +80,20 @@ func TestServerValidateDataSourceConfig(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetDataSourcesMethod: func(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { - return map[string]provider.DataSourceType{ - "test_data_source": &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSource{}, nil - }, + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + DataSource: &testprovider.DataSource{}, + } }, - }, nil + } }, }, }, @@ -103,23 +108,24 @@ func TestServerValidateDataSourceConfig(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetDataSourcesMethod: func(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { - return map[string]provider.DataSourceType{ - "test_data_source": &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSourceWithValidateConfig{ - DataSource: &testprovider.DataSource{}, - ValidateConfigMethod: func(ctx context.Context, req datasource.ValidateConfigRequest, resp *datasource.ValidateConfigResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil - }, + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadataAndValidateConfig{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + DataSource: &testprovider.DataSource{}, + ValidateConfigMethod: func(ctx context.Context, req datasource.ValidateConfigRequest, resp *datasource.ValidateConfigResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") + }, + } }, - }, nil + } }, }, }, diff --git a/internal/proto5server/server_validateresourcetypeconfig.go b/internal/proto5server/server_validateresourcetypeconfig.go index 9d27153b2..9572d22f0 100644 --- a/internal/proto5server/server_validateresourcetypeconfig.go +++ b/internal/proto5server/server_validateresourcetypeconfig.go @@ -17,7 +17,7 @@ func (s *Server) ValidateResourceTypeConfig(ctx context.Context, proto5Req *tfpr fwResp := &fwserver.ValidateResourceConfigResponse{} - resourceType, diags := s.FrameworkServer.ResourceType(ctx, proto5Req.TypeName) + resource, diags := s.FrameworkServer.Resource(ctx, proto5Req.TypeName) fwResp.Diagnostics.Append(diags...) @@ -33,7 +33,7 @@ func (s *Server) ValidateResourceTypeConfig(ctx context.Context, proto5Req *tfpr return toproto5.ValidateResourceTypeConfigResponse(ctx, fwResp), nil } - fwReq, diags := fromproto5.ValidateResourceTypeConfigRequest(ctx, proto5Req, resourceType, resourceSchema) + fwReq, diags := fromproto5.ValidateResourceTypeConfigRequest(ctx, proto5Req, resource, resourceSchema) fwResp.Diagnostics.Append(diags...) diff --git a/internal/proto5server/server_validateresourcetypeconfig_test.go b/internal/proto5server/server_validateresourcetypeconfig_test.go index 81bb3d469..f11059271 100644 --- a/internal/proto5server/server_validateresourcetypeconfig_test.go +++ b/internal/proto5server/server_validateresourcetypeconfig_test.go @@ -8,7 +8,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" - "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" @@ -54,23 +53,26 @@ func TestServerValidateResourceTypeConfig(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_data_source": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return tfsdk.Schema{}, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{}, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + } }, - }, nil + } }, }, }, }, request: &tfprotov5.ValidateResourceTypeConfigRequest{ - TypeName: "test_data_source", + TypeName: "test_resource", }, expectedResponse: &tfprotov5.ValidateResourceTypeConfigResponse{}, }, @@ -78,24 +80,27 @@ func TestServerValidateResourceTypeConfig(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_data_source": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + } }, - }, nil + } }, }, }, }, request: &tfprotov5.ValidateResourceTypeConfigRequest{ Config: &testDynamicValue, - TypeName: "test_data_source", + TypeName: "test_resource", }, expectedResponse: &tfprotov5.ValidateResourceTypeConfigResponse{}, }, @@ -103,30 +108,31 @@ func TestServerValidateResourceTypeConfig(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_data_source": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithValidateConfig{ - Resource: &testprovider.Resource{}, - ValidateConfigMethod: func(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadataAndValidateConfig{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + ValidateConfigMethod: func(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") + }, + } }, - }, nil + } }, }, }, }, request: &tfprotov5.ValidateResourceTypeConfigRequest{ Config: &testDynamicValue, - TypeName: "test_data_source", + TypeName: "test_resource", }, expectedResponse: &tfprotov5.ValidateResourceTypeConfigResponse{ Diagnostics: []*tfprotov5.Diagnostic{ diff --git a/internal/proto6server/server_applyresourcechange.go b/internal/proto6server/server_applyresourcechange.go index af9f99f7f..101603c1b 100644 --- a/internal/proto6server/server_applyresourcechange.go +++ b/internal/proto6server/server_applyresourcechange.go @@ -17,7 +17,7 @@ func (s *Server) ApplyResourceChange(ctx context.Context, proto6Req *tfprotov6.A fwResp := &fwserver.ApplyResourceChangeResponse{} - resourceType, diags := s.FrameworkServer.ResourceType(ctx, proto6Req.TypeName) + resource, diags := s.FrameworkServer.Resource(ctx, proto6Req.TypeName) fwResp.Diagnostics.Append(diags...) @@ -41,7 +41,7 @@ func (s *Server) ApplyResourceChange(ctx context.Context, proto6Req *tfprotov6.A return toproto6.ApplyResourceChangeResponse(ctx, fwResp), nil } - fwReq, diags := fromproto6.ApplyResourceChangeRequest(ctx, proto6Req, resourceType, resourceSchema, providerMetaSchema) + fwReq, diags := fromproto6.ApplyResourceChangeRequest(ctx, proto6Req, resource, resourceSchema, providerMetaSchema) fwResp.Diagnostics.Append(diags...) diff --git a/internal/proto6server/server_applyresourcechange_test.go b/internal/proto6server/server_applyresourcechange_test.go index 5c430e784..51389409b 100644 --- a/internal/proto6server/server_applyresourcechange_test.go +++ b/internal/proto6server/server_applyresourcechange_test.go @@ -13,7 +13,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" - "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" @@ -82,14 +81,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var data testSchemaData @@ -108,10 +110,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -139,14 +141,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var data testSchemaData @@ -165,10 +170,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -197,14 +202,17 @@ func TestServerApplyResourceChange(t *testing.T) { FrameworkServer: fwserver.Server{ Provider: &testprovider.ProviderWithMetaSchema{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var metadata testProviderMetaData @@ -226,10 +234,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, GetMetaSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { @@ -262,14 +270,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddWarning("warning summary", "warning detail") resp.Diagnostics.AddError("error summary", "error detail") @@ -280,10 +291,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -320,14 +331,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var data testSchemaData @@ -340,10 +354,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -371,14 +385,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // Intentionally missing resp.State.Set() }, @@ -388,10 +405,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -426,14 +443,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var data testSchemaData @@ -450,10 +470,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Create, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -475,14 +495,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") }, @@ -498,10 +521,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -523,14 +546,17 @@ func TestServerApplyResourceChange(t *testing.T) { FrameworkServer: fwserver.Server{ Provider: &testprovider.ProviderWithMetaSchema{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") }, @@ -546,10 +572,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, GetMetaSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { @@ -575,14 +601,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") }, @@ -602,10 +631,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -628,14 +657,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") }, @@ -646,10 +678,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -685,14 +717,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Create") }, @@ -702,10 +737,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Delete, Got: Update") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -726,14 +761,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") @@ -750,10 +788,10 @@ func TestServerApplyResourceChange(t *testing.T) { resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -785,14 +823,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") @@ -809,10 +850,10 @@ func TestServerApplyResourceChange(t *testing.T) { resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestComputed.Value) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -844,14 +885,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") }, @@ -867,10 +911,10 @@ func TestServerApplyResourceChange(t *testing.T) { resp.Diagnostics.AddError("Unexpected req.State Value", "Got: "+data.TestRequired.Value) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -903,14 +947,17 @@ func TestServerApplyResourceChange(t *testing.T) { FrameworkServer: fwserver.Server{ Provider: &testprovider.ProviderWithMetaSchema{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") }, @@ -926,10 +973,10 @@ func TestServerApplyResourceChange(t *testing.T) { resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, GetMetaSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { @@ -967,14 +1014,17 @@ func TestServerApplyResourceChange(t *testing.T) { FrameworkServer: fwserver.Server{ Provider: &testprovider.ProviderWithMetaSchema{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") }, @@ -994,10 +1044,10 @@ func TestServerApplyResourceChange(t *testing.T) { ) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, GetMetaSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { @@ -1038,14 +1088,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") }, @@ -1056,10 +1109,10 @@ func TestServerApplyResourceChange(t *testing.T) { resp.Diagnostics.AddWarning("warning summary", "warning detail") resp.Diagnostics.AddError("error summary", "error detail") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -1102,14 +1155,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") }, @@ -1122,10 +1178,10 @@ func TestServerApplyResourceChange(t *testing.T) { resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -1156,14 +1212,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") }, @@ -1173,10 +1232,10 @@ func TestServerApplyResourceChange(t *testing.T) { UpdateMethod: func(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { resp.State.RemoveResource(ctx) }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -1212,14 +1271,17 @@ func TestServerApplyResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ CreateMethod: func(_ context.Context, _ resource.CreateRequest, resp *resource.CreateResponse) { resp.Diagnostics.AddError("Unexpected Method Call", "Expected: Update, Got: Create") }, @@ -1231,10 +1293,10 @@ func TestServerApplyResourceChange(t *testing.T) { resp.Diagnostics.Append(diags...) }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, diff --git a/internal/proto6server/server_getproviderschema_test.go b/internal/proto6server/server_getproviderschema_test.go index ba8cdadd3..bc9816fe6 100644 --- a/internal/proto6server/server_getproviderschema_test.go +++ b/internal/proto6server/server_getproviderschema_test.go @@ -6,11 +6,13 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" "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" "github.com/hashicorp/terraform-plugin-go/tfprotov6" @@ -27,10 +29,278 @@ func TestServerGetProviderSchema(t *testing.T) { expectedError error expectedResponse *tfprotov6.GetProviderSchemaResponse }{ - "datasourceschemas": { + "datasourceschemas-DataSources": { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source1" + }, + } + }, + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test2": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source2" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov6.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov6.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov6.Schema{ + "test_data_source1": { + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "test1", + Required: true, + Type: tftypes.String, + }, + }, + }, + }, + "test_data_source2": { + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "test2", + Required: true, + Type: tftypes.String, + }, + }, + }, + }, + }, + Provider: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov6.Schema{}, + ServerCapabilities: &tfprotov6.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "datasourceschemas-DataSources-duplicate-type-name": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + } + }, + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test2": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov6.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov6.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov6.Schema{}, + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "Duplicate Data Source Type Defined", + Detail: "The test_data_source data source type name was returned for multiple data sources. " + + "Data source type names must be unique. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + Provider: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov6.Schema{}, + ServerCapabilities: &tfprotov6.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "datasourceschemas-DataSources-empty-type-name": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithMetadata{ + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov6.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov6.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov6.Schema{}, + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "Data Source Type Name Missing", + Detail: "The *testprovider.DataSourceWithMetadata DataSource returned an empty string from the Metadata method. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + Provider: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov6.Schema{}, + ServerCapabilities: &tfprotov6.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "datasourceschemas-DataSources-missing-schema": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithMetadata{ + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov6.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov6.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov6.Schema{}, + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "Data Source Schema Missing", + Detail: "The *testprovider.DataSourceWithMetadata DataSource in the provider is missing the GetSchema method. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + Provider: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov6.Schema{}, + ServerCapabilities: &tfprotov6.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "datasourceschemas-DataSources-missing-type-name": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchema{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov6.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov6.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov6.Schema{}, + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "Data Source Type Name Missing", + Detail: "The *testprovider.DataSourceWithGetSchema DataSource in the provider DataSources method results is missing the Metadata method. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + Provider: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov6.Schema{}, + ServerCapabilities: &tfprotov6.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "datasourceschemas-GetDataSources": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.ProviderWithGetDataSources{ + //nolint:staticcheck // Internal implementation GetDataSourcesMethod: func(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { return map[string]provider.DataSourceType{ "test_data_source1": &testprovider.DataSourceType{ @@ -175,10 +445,278 @@ func TestServerGetProviderSchema(t *testing.T) { }, }, }, - "resourceschemas": { + "resourceschemas-Resources": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource1" + }, + } + }, + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test2": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource2" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov6.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov6.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov6.Schema{}, + Provider: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov6.Schema{ + "test_resource1": { + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "test1", + Required: true, + Type: tftypes.String, + }, + }, + }, + }, + "test_resource2": { + Block: &tfprotov6.SchemaBlock{ + Attributes: []*tfprotov6.SchemaAttribute{ + { + Name: "test2", + Required: true, + Type: tftypes.String, + }, + }, + }, + }, + }, + ServerCapabilities: &tfprotov6.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "resourceschemas-Resources-duplicate-type-name": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + } + }, + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test2": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov6.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov6.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov6.Schema{}, + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "Duplicate Resource Type Defined", + Detail: "The test_resource resource type name was returned for multiple resources. " + + "Resource type names must be unique. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + Provider: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov6.Schema{}, + ServerCapabilities: &tfprotov6.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "resourceschemas-Resources-empty-type-name": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithMetadata{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov6.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov6.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov6.Schema{}, + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "Resource Type Name Missing", + Detail: "The *testprovider.ResourceWithMetadata Resource returned an empty string from the Metadata method. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + Provider: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov6.Schema{}, + ServerCapabilities: &tfprotov6.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "resourceschemas-Resources-missing-schema": { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithMetadata{ + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov6.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov6.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov6.Schema{}, + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "Resource Schema Missing", + Detail: "The *testprovider.ResourceWithMetadata Resource in the provider is missing the GetSchema method. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + Provider: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov6.Schema{}, + ServerCapabilities: &tfprotov6.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "resourceschemas-Resources-missing-type-name": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.Provider{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchema{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "test1": { + Required: true, + Type: types.StringType, + }, + }, + }, nil + }, + } + }, + } + }, + }, + }, + }, + request: &tfprotov6.GetProviderSchemaRequest{}, + expectedResponse: &tfprotov6.GetProviderSchemaResponse{ + DataSourceSchemas: map[string]*tfprotov6.Schema{}, + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "Resource Type Name Missing", + Detail: "The *testprovider.ResourceWithGetSchema Resource in the provider Resources method results is missing the Metadata method. " + + "This is always an issue with the provider and should be reported to the provider developers.", + }, + }, + Provider: &tfprotov6.Schema{ + Block: &tfprotov6.SchemaBlock{}, + }, + ResourceSchemas: map[string]*tfprotov6.Schema{}, + ServerCapabilities: &tfprotov6.ServerCapabilities{ + PlanDestroy: true, + }, + }, + }, + "resourceschemas-GetResources": { + server: &Server{ + FrameworkServer: fwserver.Server{ + Provider: &testprovider.ProviderWithGetResources{ + //nolint:staticcheck // Internal implementation GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { return map[string]provider.ResourceType{ "test_resource1": &testprovider.ResourceType{ @@ -320,12 +858,17 @@ func TestServerGetProviderSchema_logging(t *testing.T) { }, { "@level": "debug", - "@message": "Calling provider defined Provider GetResources", + "@message": "Calling provider defined Provider Resources", "@module": "sdk.framework", }, { "@level": "debug", - "@message": "Called provider defined Provider GetResources", + "@message": "Called provider defined Provider Resources", + "@module": "sdk.framework", + }, + { + "@level": "trace", + "@message": "Checking ResourceTypes lock", "@module": "sdk.framework", }, { @@ -340,12 +883,17 @@ func TestServerGetProviderSchema_logging(t *testing.T) { }, { "@level": "debug", - "@message": "Calling provider defined Provider GetDataSources", + "@message": "Calling provider defined Provider DataSources", "@module": "sdk.framework", }, { "@level": "debug", - "@message": "Called provider defined Provider GetDataSources", + "@message": "Called provider defined Provider DataSources", + "@module": "sdk.framework", + }, + { + "@level": "trace", + "@message": "Checking DataSourceTypes lock", "@module": "sdk.framework", }, } diff --git a/internal/proto6server/server_importresourcestate.go b/internal/proto6server/server_importresourcestate.go index 68767ce3f..8743508f2 100644 --- a/internal/proto6server/server_importresourcestate.go +++ b/internal/proto6server/server_importresourcestate.go @@ -17,7 +17,7 @@ func (s *Server) ImportResourceState(ctx context.Context, proto6Req *tfprotov6.I fwResp := &fwserver.ImportResourceStateResponse{} - resourceType, diags := s.FrameworkServer.ResourceType(ctx, proto6Req.TypeName) + resource, diags := s.FrameworkServer.Resource(ctx, proto6Req.TypeName) fwResp.Diagnostics.Append(diags...) @@ -33,7 +33,7 @@ func (s *Server) ImportResourceState(ctx context.Context, proto6Req *tfprotov6.I return toproto6.ImportResourceStateResponse(ctx, fwResp), nil } - fwReq, diags := fromproto6.ImportResourceStateRequest(ctx, proto6Req, resourceType, resourceSchema) + fwReq, diags := fromproto6.ImportResourceStateRequest(ctx, proto6Req, resource, resourceSchema) fwResp.Diagnostics.Append(diags...) diff --git a/internal/proto6server/server_importresourcestate_test.go b/internal/proto6server/server_importresourcestate_test.go index 67e9e64d9..cb8807f37 100644 --- a/internal/proto6server/server_importresourcestate_test.go +++ b/internal/proto6server/server_importresourcestate_test.go @@ -13,7 +13,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" "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" @@ -63,26 +62,27 @@ func TestServerImportResourceState(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithImportState{ - Resource: &testprovider.Resource{}, - ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { - if req.ID != "test-id" { - resp.Diagnostics.AddError("unexpected req.ID value: %s", req.ID) - } - - resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndImportStateAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + if req.ID != "test-id" { + resp.Diagnostics.AddError("unexpected req.ID value: %s", req.ID) + } + + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) + }, + } }, - }, nil + } }, }, }, @@ -104,23 +104,24 @@ func TestServerImportResourceState(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithImportState{ - Resource: &testprovider.Resource{}, - ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndImportStateAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") + }, + } }, - }, nil + } }, }, }, @@ -148,22 +149,23 @@ func TestServerImportResourceState(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithImportState{ - Resource: &testprovider.Resource{}, - ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { - resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndImportStateAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) + }, + } }, - }, nil + } }, }, }, @@ -185,26 +187,27 @@ func TestServerImportResourceState(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithImportState{ - Resource: &testprovider.Resource{}, - ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { - diags := resp.Private.SetKey(ctx, "providerKey", []byte(`{"key": "value"}`)) - - resp.Diagnostics.Append(diags...) - - resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndImportStateAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + ImportStateMethod: func(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + diags := resp.Private.SetKey(ctx, "providerKey", []byte(`{"key": "value"}`)) + + resp.Diagnostics.Append(diags...) + + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) + }, + } }, - }, nil + } }, }, }, diff --git a/internal/proto6server/server_planresourcechange.go b/internal/proto6server/server_planresourcechange.go index 793027847..73a812387 100644 --- a/internal/proto6server/server_planresourcechange.go +++ b/internal/proto6server/server_planresourcechange.go @@ -17,7 +17,7 @@ func (s *Server) PlanResourceChange(ctx context.Context, proto6Req *tfprotov6.Pl fwResp := &fwserver.PlanResourceChangeResponse{} - resourceType, diags := s.FrameworkServer.ResourceType(ctx, proto6Req.TypeName) + resource, diags := s.FrameworkServer.Resource(ctx, proto6Req.TypeName) fwResp.Diagnostics.Append(diags...) @@ -41,7 +41,7 @@ func (s *Server) PlanResourceChange(ctx context.Context, proto6Req *tfprotov6.Pl return toproto6.PlanResourceChangeResponse(ctx, fwResp), nil } - fwReq, diags := fromproto6.PlanResourceChangeRequest(ctx, proto6Req, resourceType, resourceSchema, providerMetaSchema) + fwReq, diags := fromproto6.PlanResourceChangeRequest(ctx, proto6Req, resource, resourceSchema, providerMetaSchema) fwResp.Diagnostics.Append(diags...) diff --git a/internal/proto6server/server_planresourcechange_test.go b/internal/proto6server/server_planresourcechange_test.go index e652515f2..0ff05ea36 100644 --- a/internal/proto6server/server_planresourcechange_test.go +++ b/internal/proto6server/server_planresourcechange_test.go @@ -9,7 +9,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" "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" @@ -80,27 +79,28 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - if data.TestRequired.Value != "test-config-value" { - resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) - } - }, - }, nil - }, + if data.TestRequired.Value != "test-config-value" { + resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) + } + }, + } }, - }, nil + } }, }, }, @@ -128,27 +128,28 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - if !data.TestComputed.Unknown { - resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestComputed.Value) - } - }, - }, nil - }, + if !data.TestComputed.Unknown { + resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestComputed.Value) + } + }, + } }, - }, nil + } }, }, }, @@ -177,27 +178,28 @@ func TestServerPlanResourceChange(t *testing.T) { FrameworkServer: fwserver.Server{ Provider: &testprovider.ProviderWithMetaSchema{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testProviderMetaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testProviderMetaData - resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) + resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) - if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { - resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) - } - }, - }, nil - }, + if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { + resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) + } + }, + } }, - }, nil + } }, }, GetMetaSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { @@ -230,22 +232,23 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") + }, + } }, - }, nil + } }, }, }, @@ -285,27 +288,28 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - data.TestComputed = types.String{Value: "test-plannedstate-value"} + data.TestComputed = types.String{Value: "test-plannedstate-value"} - resp.Diagnostics.Append(resp.Plan.Set(ctx, &data)...) - }, - }, nil - }, + resp.Diagnostics.Append(resp.Plan.Set(ctx, &data)...) + }, + } }, - }, nil + } }, }, }, @@ -333,29 +337,30 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - // This is a strange thing to signal on creation, - // but the framework does not prevent you from - // doing it and it might be overly burdensome on - // provider developers to have the framework raise - // an error if it is technically valid in the - // protocol. - resp.RequiresReplace = path.Paths{ - path.Root("test_required"), - } - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + // This is a strange thing to signal on creation, + // but the framework does not prevent you from + // doing it and it might be overly burdensome on + // provider developers to have the framework raise + // an error if it is technically valid in the + // protocol. + resp.RequiresReplace = path.Paths{ + path.Root("test_required"), + } + }, + } }, - }, nil + } }, }, }, @@ -386,27 +391,28 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) - if data.TestRequired.Value != "test-priorstate-value" { - resp.Diagnostics.AddError("Unexpected req.State Value", "Got: "+data.TestRequired.Value) - } - }, - }, nil - }, + if data.TestRequired.Value != "test-priorstate-value" { + resp.Diagnostics.AddError("Unexpected req.State Value", "Got: "+data.TestRequired.Value) + } + }, + } }, - }, nil + } }, }, }, @@ -428,27 +434,28 @@ func TestServerPlanResourceChange(t *testing.T) { FrameworkServer: fwserver.Server{ Provider: &testprovider.ProviderWithMetaSchema{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testProviderMetaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testProviderMetaData - resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) + resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) - if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { - resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) - } - }, - }, nil - }, + if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { + resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) + } + }, + } }, - }, nil + } }, }, GetMetaSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { @@ -474,22 +481,23 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") + }, + } }, - }, nil + } }, }, }, @@ -522,22 +530,23 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - // This is invalid logic to run during deletion. - resp.Diagnostics.Append(resp.Plan.SetAttribute(ctx, path.Root("test_computed"), types.String{Value: "test-plannedstate-value"})...) - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + // This is invalid logic to run during deletion. + resp.Diagnostics.Append(resp.Plan.SetAttribute(ctx, path.Root("test_computed"), types.String{Value: "test-plannedstate-value"})...) + }, + } }, - }, nil + } }, }, }, @@ -570,29 +579,30 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - // This is a strange thing to signal on destroy, - // but the framework does not prevent you from - // doing it and it might be overly burdensome on - // provider developers to have the framework raise - // an error if it is technically valid in the - // protocol. - resp.RequiresReplace = path.Paths{ - path.Root("test_required"), - } - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + // This is a strange thing to signal on destroy, + // but the framework does not prevent you from + // doing it and it might be overly burdensome on + // provider developers to have the framework raise + // an error if it is technically valid in the + // protocol. + resp.RequiresReplace = path.Paths{ + path.Root("test_required"), + } + }, + } }, - }, nil + } }, }, }, @@ -616,27 +626,28 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - if data.TestRequired.Value != "test-new-value" { - resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) - } - }, - }, nil - }, + if data.TestRequired.Value != "test-new-value" { + resp.Diagnostics.AddError("Unexpected req.Config Value", "Got: "+data.TestRequired.Value) + } + }, + } }, - }, nil + } }, }, }, @@ -667,27 +678,28 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - if !data.TestComputed.Unknown { - resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestComputed.Value) - } - }, - }, nil - }, + if !data.TestComputed.Unknown { + resp.Diagnostics.AddError("Unexpected req.Plan Value", "Got: "+data.TestComputed.Value) + } + }, + } }, - }, nil + } }, }, }, @@ -718,27 +730,28 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) - if data.TestRequired.Value != "test-old-value" { - resp.Diagnostics.AddError("Unexpected req.State Value", "Got: "+data.TestRequired.Value) - } - }, - }, nil - }, + if data.TestRequired.Value != "test-old-value" { + resp.Diagnostics.AddError("Unexpected req.State Value", "Got: "+data.TestRequired.Value) + } + }, + } }, - }, nil + } }, }, }, @@ -770,27 +783,28 @@ func TestServerPlanResourceChange(t *testing.T) { FrameworkServer: fwserver.Server{ Provider: &testprovider.ProviderWithMetaSchema{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testProviderMetaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testProviderMetaData - resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) + resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &data)...) - if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { - resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) - } - }, - }, nil - }, + if data.TestProviderMetaAttribute.Value != "test-provider-meta-value" { + resp.Diagnostics.AddError("Unexpected req.ProviderMeta Value", "Got: "+data.TestProviderMetaAttribute.Value) + } + }, + } }, - }, nil + } }, }, GetMetaSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { @@ -826,22 +840,23 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") + }, + } }, - }, nil + } }, }, }, @@ -884,27 +899,28 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - var data testSchemaData + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + var data testSchemaData - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - data.TestComputed = types.String{Value: "test-plannedstate-value"} + data.TestComputed = types.String{Value: "test-plannedstate-value"} - resp.Diagnostics.Append(resp.Plan.Set(ctx, &data)...) - }, - }, nil - }, + resp.Diagnostics.Append(resp.Plan.Set(ctx, &data)...) + }, + } }, - }, nil + } }, }, }, @@ -935,23 +951,24 @@ func TestServerPlanResourceChange(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithModifyPlan{ - ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { - resp.RequiresReplace = path.Paths{ - path.Root("test_required"), - } - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndModifyPlanAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + ModifyPlanMethod: func(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + resp.RequiresReplace = path.Paths{ + path.Root("test_required"), + } + }, + } }, - }, nil + } }, }, }, diff --git a/internal/proto6server/server_readdatasource.go b/internal/proto6server/server_readdatasource.go index d11509c5d..7af936df1 100644 --- a/internal/proto6server/server_readdatasource.go +++ b/internal/proto6server/server_readdatasource.go @@ -17,7 +17,7 @@ func (s *Server) ReadDataSource(ctx context.Context, proto6Req *tfprotov6.ReadDa fwResp := &fwserver.ReadDataSourceResponse{} - dataSourceType, diags := s.FrameworkServer.DataSourceType(ctx, proto6Req.TypeName) + dataSource, diags := s.FrameworkServer.DataSource(ctx, proto6Req.TypeName) fwResp.Diagnostics.Append(diags...) @@ -41,7 +41,7 @@ func (s *Server) ReadDataSource(ctx context.Context, proto6Req *tfprotov6.ReadDa return toproto6.ReadDataSourceResponse(ctx, fwResp), nil } - fwReq, diags := fromproto6.ReadDataSourceRequest(ctx, proto6Req, dataSourceType, dataSourceSchema, providerMetaSchema) + fwReq, diags := fromproto6.ReadDataSourceRequest(ctx, proto6Req, dataSource, dataSourceSchema, providerMetaSchema) fwResp.Diagnostics.Append(diags...) diff --git a/internal/proto6server/server_readdatasource_test.go b/internal/proto6server/server_readdatasource_test.go index b77c3a4d8..1743a42b0 100644 --- a/internal/proto6server/server_readdatasource_test.go +++ b/internal/proto6server/server_readdatasource_test.go @@ -9,7 +9,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" - "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-go/tfprotov6" @@ -61,17 +60,20 @@ func TestServerReadDataSource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetDataSourcesMethod: func(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { - return map[string]provider.DataSourceType{ - "test_data_source": &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return tfsdk.Schema{}, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSource{}, nil - }, + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{}, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + DataSource: &testprovider.DataSource{}, + } }, - }, nil + } }, }, }, @@ -88,14 +90,17 @@ func TestServerReadDataSource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetDataSourcesMethod: func(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { - return map[string]provider.DataSourceType{ - "test_data_source": &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSource{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + DataSource: &testprovider.DataSource{ ReadMethod: func(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { var config struct { TestComputed types.String `tfsdk:"test_computed"` @@ -108,10 +113,10 @@ func TestServerReadDataSource(t *testing.T) { resp.Diagnostics.AddError("unexpected req.Config value: %s", config.TestRequired.Value) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -129,14 +134,17 @@ func TestServerReadDataSource(t *testing.T) { FrameworkServer: fwserver.Server{ Provider: &testprovider.ProviderWithMetaSchema{ Provider: &testprovider.Provider{ - GetDataSourcesMethod: func(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { - return map[string]provider.DataSourceType{ - "test_data_source": &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return tfsdk.Schema{}, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSource{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{}, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + DataSource: &testprovider.DataSource{ ReadMethod: func(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { var config struct { TestComputed types.String `tfsdk:"test_computed"` @@ -149,10 +157,10 @@ func TestServerReadDataSource(t *testing.T) { resp.Diagnostics.AddError("unexpected req.ProviderMeta value: %s", config.TestRequired.Value) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, GetMetaSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { @@ -174,22 +182,25 @@ func TestServerReadDataSource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetDataSourcesMethod: func(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { - return map[string]provider.DataSourceType{ - "test_data_source": &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSource{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + DataSource: &testprovider.DataSource{ ReadMethod: func(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { resp.Diagnostics.AddWarning("warning summary", "warning detail") resp.Diagnostics.AddError("error summary", "error detail") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -218,14 +229,17 @@ func TestServerReadDataSource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetDataSourcesMethod: func(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { - return map[string]provider.DataSourceType{ - "test_data_source": &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSource{ + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + DataSource: &testprovider.DataSource{ ReadMethod: func(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { var data struct { TestComputed types.String `tfsdk:"test_computed"` @@ -238,10 +252,10 @@ func TestServerReadDataSource(t *testing.T) { resp.Diagnostics.Append(resp.State.Set(ctx, data)...) }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, diff --git a/internal/proto6server/server_readresource.go b/internal/proto6server/server_readresource.go index 404ddc7c9..441eec984 100644 --- a/internal/proto6server/server_readresource.go +++ b/internal/proto6server/server_readresource.go @@ -17,7 +17,7 @@ func (s *Server) ReadResource(ctx context.Context, proto6Req *tfprotov6.ReadReso fwResp := &fwserver.ReadResourceResponse{} - resourceType, diags := s.FrameworkServer.ResourceType(ctx, proto6Req.TypeName) + resource, diags := s.FrameworkServer.Resource(ctx, proto6Req.TypeName) fwResp.Diagnostics.Append(diags...) @@ -41,7 +41,7 @@ func (s *Server) ReadResource(ctx context.Context, proto6Req *tfprotov6.ReadReso return toproto6.ReadResourceResponse(ctx, fwResp), nil } - fwReq, diags := fromproto6.ReadResourceRequest(ctx, proto6Req, resourceType, resourceSchema, providerMetaSchema) + fwReq, diags := fromproto6.ReadResourceRequest(ctx, proto6Req, resource, resourceSchema, providerMetaSchema) fwResp.Diagnostics.Append(diags...) diff --git a/internal/proto6server/server_readresource_test.go b/internal/proto6server/server_readresource_test.go index 746047fc1..d3f611f45 100644 --- a/internal/proto6server/server_readresource_test.go +++ b/internal/proto6server/server_readresource_test.go @@ -13,7 +13,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/privatestate" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" - "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" @@ -66,17 +65,20 @@ func TestServerReadResource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return tfsdk.Schema{}, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{}, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + } }, - }, nil + } }, }, }, @@ -93,14 +95,17 @@ func TestServerReadResource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var data struct { TestComputed types.String `tfsdk:"test_computed"` @@ -113,10 +118,10 @@ func TestServerReadResource(t *testing.T) { resp.Diagnostics.AddError("unexpected req.State value: %s", data.TestRequired.Value) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -134,14 +139,17 @@ func TestServerReadResource(t *testing.T) { FrameworkServer: fwserver.Server{ Provider: &testprovider.ProviderWithMetaSchema{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return tfsdk.Schema{}, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{}, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var data struct { TestComputed types.String `tfsdk:"test_computed"` @@ -154,10 +162,10 @@ func TestServerReadResource(t *testing.T) { resp.Diagnostics.AddError("unexpected req.ProviderMeta value: %s", data.TestRequired.Value) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, GetMetaSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { @@ -179,14 +187,17 @@ func TestServerReadResource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return tfsdk.Schema{}, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{}, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { expected := `{"pKeyOne": {"k0": "zero", "k1": 1}}` got, diags := req.Private.GetKey(ctx, "providerKey") @@ -200,10 +211,10 @@ func TestServerReadResource(t *testing.T) { ) } }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -228,22 +239,25 @@ func TestServerReadResource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { resp.Diagnostics.AddWarning("warning summary", "warning detail") resp.Diagnostics.AddError("error summary", "error detail") }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -272,14 +286,17 @@ func TestServerReadResource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var data struct { TestComputed types.String `tfsdk:"test_computed"` @@ -292,10 +309,10 @@ func TestServerReadResource(t *testing.T) { resp.Diagnostics.Append(resp.State.Set(ctx, data)...) }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -312,21 +329,24 @@ func TestServerReadResource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { resp.State.RemoveResource(ctx) }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, @@ -343,23 +363,26 @@ func TestServerReadResource(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return tfsdk.Schema{}, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{ + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{}, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{ ReadMethod: func(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { diags := resp.Private.SetKey(ctx, "providerKey", []byte(`{"key": "value"}`)) resp.Diagnostics.Append(diags...) }, - }, nil - }, + }, + } }, - }, nil + } }, }, }, diff --git a/internal/proto6server/server_upgraderesourcestate.go b/internal/proto6server/server_upgraderesourcestate.go index 289182dbf..1e6049c02 100644 --- a/internal/proto6server/server_upgraderesourcestate.go +++ b/internal/proto6server/server_upgraderesourcestate.go @@ -21,7 +21,7 @@ func (s *Server) UpgradeResourceState(ctx context.Context, proto6Req *tfprotov6. return toproto6.UpgradeResourceStateResponse(ctx, fwResp), nil } - resourceType, diags := s.FrameworkServer.ResourceType(ctx, proto6Req.TypeName) + resource, diags := s.FrameworkServer.Resource(ctx, proto6Req.TypeName) fwResp.Diagnostics.Append(diags...) @@ -37,7 +37,7 @@ func (s *Server) UpgradeResourceState(ctx context.Context, proto6Req *tfprotov6. return toproto6.UpgradeResourceStateResponse(ctx, fwResp), nil } - fwReq, diags := fromproto6.UpgradeResourceStateRequest(ctx, proto6Req, resourceType, resourceSchema) + fwReq, diags := fromproto6.UpgradeResourceStateRequest(ctx, proto6Req, resource, resourceSchema) fwResp.Diagnostics.Append(diags...) diff --git a/internal/proto6server/server_upgraderesourcestate_test.go b/internal/proto6server/server_upgraderesourcestate_test.go index 2ca597334..dfd595df6 100644 --- a/internal/proto6server/server_upgraderesourcestate_test.go +++ b/internal/proto6server/server_upgraderesourcestate_test.go @@ -8,7 +8,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" - "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" @@ -58,45 +57,46 @@ func TestServerUpgradeResourceState(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithUpgradeState{ - Resource: &testprovider.Resource{}, - UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { - return map[int64]resource.StateUpgrader{ - 0: { - StateUpgrader: func(_ context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { - expectedRawState := testNewRawState(t, map[string]interface{}{ - "id": "test-id-value", - "required_attribute": true, - }) + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadataAndUpgradeState{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return schema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{ + 0: { + StateUpgrader: func(_ context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { + expectedRawState := testNewRawState(t, map[string]interface{}{ + "id": "test-id-value", + "required_attribute": true, + }) - if diff := cmp.Diff(req.RawState, expectedRawState); diff != "" { - resp.Diagnostics.AddError("unexpected req.RawState difference: %s", diff) - } + if diff := cmp.Diff(req.RawState, expectedRawState); diff != "" { + resp.Diagnostics.AddError("unexpected req.RawState difference: %s", diff) + } - // Prevent Missing Upgraded Resource State error - resp.State = tfsdk.State{ - Raw: tftypes.NewValue(schemaType, map[string]tftypes.Value{ - "id": tftypes.NewValue(tftypes.String, "test-id-value"), - "optional_attribute": tftypes.NewValue(tftypes.String, nil), - "required_attribute": tftypes.NewValue(tftypes.String, "true"), - }), - Schema: schema, - } - }, + // Prevent Missing Upgraded Resource State error + resp.State = tfsdk.State{ + Raw: tftypes.NewValue(schemaType, map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "test-id-value"), + "optional_attribute": tftypes.NewValue(tftypes.String, nil), + "required_attribute": tftypes.NewValue(tftypes.String, "true"), + }), + Schema: schema, + } }, - } - }, - }, nil - }, + }, + } + }, + } }, - }, nil + } }, }, }, @@ -157,29 +157,30 @@ func TestServerUpgradeResourceState(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithUpgradeState{ - Resource: &testprovider.Resource{}, - UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { - return map[int64]resource.StateUpgrader{ - 0: { - StateUpgrader: func(_ context.Context, _ resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadataAndUpgradeState{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return schema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{ + 0: { + StateUpgrader: func(_ context.Context, _ resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") }, - } - }, - }, nil - }, + }, + } + }, + } }, - }, nil + } }, }, }, @@ -211,35 +212,36 @@ func TestServerUpgradeResourceState(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_resource": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return schema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithUpgradeState{ - Resource: &testprovider.Resource{}, - UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { - return map[int64]resource.StateUpgrader{ - 0: { - StateUpgrader: func(_ context.Context, _ resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { - resp.State = tfsdk.State{ - Raw: tftypes.NewValue(schemaType, map[string]tftypes.Value{ - "id": tftypes.NewValue(tftypes.String, "test-id-value"), - "optional_attribute": tftypes.NewValue(tftypes.String, nil), - "required_attribute": tftypes.NewValue(tftypes.String, "true"), - }), - Schema: schema, - } - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadataAndUpgradeState{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return schema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + UpgradeStateMethod: func(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{ + 0: { + StateUpgrader: func(_ context.Context, _ resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { + resp.State = tfsdk.State{ + Raw: tftypes.NewValue(schemaType, map[string]tftypes.Value{ + "id": tftypes.NewValue(tftypes.String, "test-id-value"), + "optional_attribute": tftypes.NewValue(tftypes.String, nil), + "required_attribute": tftypes.NewValue(tftypes.String, "true"), + }), + Schema: schema, + } }, - } - }, - }, nil - }, + }, + } + }, + } }, - }, nil + } }, }, }, diff --git a/internal/proto6server/server_validatedataresourceconfig.go b/internal/proto6server/server_validatedataresourceconfig.go index d6b9a5d3b..8a26e4786 100644 --- a/internal/proto6server/server_validatedataresourceconfig.go +++ b/internal/proto6server/server_validatedataresourceconfig.go @@ -17,7 +17,7 @@ func (s *Server) ValidateDataResourceConfig(ctx context.Context, proto6Req *tfpr fwResp := &fwserver.ValidateDataSourceConfigResponse{} - dataSourceType, diags := s.FrameworkServer.DataSourceType(ctx, proto6Req.TypeName) + dataSource, diags := s.FrameworkServer.DataSource(ctx, proto6Req.TypeName) fwResp.Diagnostics.Append(diags...) @@ -33,7 +33,7 @@ func (s *Server) ValidateDataResourceConfig(ctx context.Context, proto6Req *tfpr return toproto6.ValidateDataSourceConfigResponse(ctx, fwResp), nil } - fwReq, diags := fromproto6.ValidateDataSourceConfigRequest(ctx, proto6Req, dataSourceType, dataSourceSchema) + fwReq, diags := fromproto6.ValidateDataSourceConfigRequest(ctx, proto6Req, dataSource, dataSourceSchema) fwResp.Diagnostics.Append(diags...) diff --git a/internal/proto6server/server_validatedataresourceconfig_test.go b/internal/proto6server/server_validatedataresourceconfig_test.go index 59be0a1ce..43b1f151d 100644 --- a/internal/proto6server/server_validatedataresourceconfig_test.go +++ b/internal/proto6server/server_validatedataresourceconfig_test.go @@ -9,7 +9,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" - "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-go/tfprotov6" @@ -54,17 +53,20 @@ func TestServerValidateDataResourceConfig(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetDataSourcesMethod: func(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { - return map[string]provider.DataSourceType{ - "test_data_source": &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return tfsdk.Schema{}, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSource{}, nil - }, + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{}, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + DataSource: &testprovider.DataSource{}, + } }, - }, nil + } }, }, }, @@ -78,17 +80,20 @@ func TestServerValidateDataResourceConfig(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetDataSourcesMethod: func(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { - return map[string]provider.DataSourceType{ - "test_data_source": &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSource{}, nil - }, + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + DataSource: &testprovider.DataSource{}, + } }, - }, nil + } }, }, }, @@ -103,23 +108,24 @@ func TestServerValidateDataResourceConfig(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetDataSourcesMethod: func(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { - return map[string]provider.DataSourceType{ - "test_data_source": &testprovider.DataSourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewDataSourceMethod: func(_ context.Context, _ provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return &testprovider.DataSourceWithValidateConfig{ - DataSource: &testprovider.DataSource{}, - ValidateConfigMethod: func(ctx context.Context, req datasource.ValidateConfigRequest, resp *datasource.ValidateConfigResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil - }, + DataSourcesMethod: func(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &testprovider.DataSourceWithGetSchemaAndMetadataAndValidateConfig{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "test_data_source" + }, + DataSource: &testprovider.DataSource{}, + ValidateConfigMethod: func(ctx context.Context, req datasource.ValidateConfigRequest, resp *datasource.ValidateConfigResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") + }, + } }, - }, nil + } }, }, }, diff --git a/internal/proto6server/server_validateresourceconfig.go b/internal/proto6server/server_validateresourceconfig.go index c2dfb577e..583f4560f 100644 --- a/internal/proto6server/server_validateresourceconfig.go +++ b/internal/proto6server/server_validateresourceconfig.go @@ -17,7 +17,7 @@ func (s *Server) ValidateResourceConfig(ctx context.Context, proto6Req *tfprotov fwResp := &fwserver.ValidateResourceConfigResponse{} - resourceType, diags := s.FrameworkServer.ResourceType(ctx, proto6Req.TypeName) + resource, diags := s.FrameworkServer.Resource(ctx, proto6Req.TypeName) fwResp.Diagnostics.Append(diags...) @@ -33,7 +33,7 @@ func (s *Server) ValidateResourceConfig(ctx context.Context, proto6Req *tfprotov return toproto6.ValidateResourceConfigResponse(ctx, fwResp), nil } - fwReq, diags := fromproto6.ValidateResourceConfigRequest(ctx, proto6Req, resourceType, resourceSchema) + fwReq, diags := fromproto6.ValidateResourceConfigRequest(ctx, proto6Req, resource, resourceSchema) fwResp.Diagnostics.Append(diags...) diff --git a/internal/proto6server/server_validateresourceconfig_test.go b/internal/proto6server/server_validateresourceconfig_test.go index 94a90ec21..8c9fcf24b 100644 --- a/internal/proto6server/server_validateresourceconfig_test.go +++ b/internal/proto6server/server_validateresourceconfig_test.go @@ -8,7 +8,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/testing/testprovider" - "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" @@ -54,23 +53,26 @@ func TestServerValidateResourceConfig(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_data_source": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return tfsdk.Schema{}, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{}, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + } }, - }, nil + } }, }, }, }, request: &tfprotov6.ValidateResourceConfigRequest{ - TypeName: "test_data_source", + TypeName: "test_resource", }, expectedResponse: &tfprotov6.ValidateResourceConfigResponse{}, }, @@ -78,24 +80,27 @@ func TestServerValidateResourceConfig(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_data_source": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.Resource{}, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadata{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + } }, - }, nil + } }, }, }, }, request: &tfprotov6.ValidateResourceConfigRequest{ Config: &testDynamicValue, - TypeName: "test_data_source", + TypeName: "test_resource", }, expectedResponse: &tfprotov6.ValidateResourceConfigResponse{}, }, @@ -103,30 +108,31 @@ func TestServerValidateResourceConfig(t *testing.T) { server: &Server{ FrameworkServer: fwserver.Server{ Provider: &testprovider.Provider{ - GetResourcesMethod: func(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "test_data_source": &testprovider.ResourceType{ - GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { - return testSchema, nil - }, - NewResourceMethod: func(_ context.Context, _ provider.Provider) (resource.Resource, diag.Diagnostics) { - return &testprovider.ResourceWithValidateConfig{ - Resource: &testprovider.Resource{}, - ValidateConfigMethod: func(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { - resp.Diagnostics.AddWarning("warning summary", "warning detail") - resp.Diagnostics.AddError("error summary", "error detail") - }, - }, nil - }, + ResourcesMethod: func(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &testprovider.ResourceWithGetSchemaAndMetadataAndValidateConfig{ + GetSchemaMethod: func(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { + return testSchema, nil + }, + MetadataMethod: func(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "test_resource" + }, + Resource: &testprovider.Resource{}, + ValidateConfigMethod: func(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { + resp.Diagnostics.AddWarning("warning summary", "warning detail") + resp.Diagnostics.AddError("error summary", "error detail") + }, + } }, - }, nil + } }, }, }, }, request: &tfprotov6.ValidateResourceConfigRequest{ Config: &testDynamicValue, - TypeName: "test_data_source", + TypeName: "test_resource", }, expectedResponse: &tfprotov6.ValidateResourceConfigResponse{ Diagnostics: []*tfprotov6.Diagnostic{ diff --git a/internal/testing/testprovider/datasourcetype.go b/internal/testing/testprovider/datasourcetype.go index 37fc8a043..c0232d0a4 100644 --- a/internal/testing/testprovider/datasourcetype.go +++ b/internal/testing/testprovider/datasourcetype.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/tfsdk" ) -var _ provider.DataSourceType = &DataSourceType{} +var _ provider.DataSourceType = &DataSourceType{} //nolint:staticcheck // Internal implementation // Declarative provider.DataSourceType for unit testing. type DataSourceType struct { diff --git a/internal/testing/testprovider/datasourcewithconfigure.go b/internal/testing/testprovider/datasourcewithconfigure.go new file mode 100644 index 000000000..4babfeecc --- /dev/null +++ b/internal/testing/testprovider/datasourcewithconfigure.go @@ -0,0 +1,27 @@ +package testprovider + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/datasource" +) + +var _ datasource.DataSource = &DataSourceWithConfigure{} +var _ datasource.DataSourceWithConfigure = &DataSourceWithConfigure{} + +// Declarative datasource.DataSourceWithConfigure for unit testing. +type DataSourceWithConfigure struct { + *DataSource + + // DataSourceWithConfigure interface methods + ConfigureMethod func(context.Context, datasource.ConfigureRequest, *datasource.ConfigureResponse) +} + +// Configure satisfies the datasource.DataSourceWithConfigure interface. +func (d *DataSourceWithConfigure) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if d.ConfigureMethod == nil { + return + } + + d.ConfigureMethod(ctx, req, resp) +} diff --git a/internal/testing/testprovider/datasourcewithgetschema.go b/internal/testing/testprovider/datasourcewithgetschema.go new file mode 100644 index 000000000..ce06cf30a --- /dev/null +++ b/internal/testing/testprovider/datasourcewithgetschema.go @@ -0,0 +1,29 @@ +package testprovider + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" +) + +var _ datasource.DataSource = &DataSourceWithGetSchema{} +var _ datasource.DataSourceWithGetSchema = &DataSourceWithGetSchema{} + +// Declarative datasource.DataSourceWithGetSchema for unit testing. +type DataSourceWithGetSchema struct { + *DataSource + + // DataSourceWithGetSchema interface methods + GetSchemaMethod func(context.Context) (tfsdk.Schema, diag.Diagnostics) +} + +// GetSchema satisfies the datasource.DataSourceWithGetSchema interface. +func (d *DataSourceWithGetSchema) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { + if d.GetSchemaMethod == nil { + return tfsdk.Schema{}, nil + } + + return d.GetSchemaMethod(ctx) +} diff --git a/internal/testing/testprovider/datasourcewithgetschema_temp.go b/internal/testing/testprovider/datasourcewithgetschema_temp.go new file mode 100644 index 000000000..b9b1a05bf --- /dev/null +++ b/internal/testing/testprovider/datasourcewithgetschema_temp.go @@ -0,0 +1,137 @@ +package testprovider + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" +) + +// This file contains temporary types until GetSchema and Metadata are required +// in DataSource. + +var _ datasource.DataSource = &DataSourceWithConfigValidatorsAndGetSchemaAndMetadata{} +var _ datasource.DataSourceWithConfigValidators = &DataSourceWithConfigValidatorsAndGetSchemaAndMetadata{} +var _ datasource.DataSourceWithGetSchema = &DataSourceWithConfigValidatorsAndGetSchemaAndMetadata{} +var _ datasource.DataSourceWithMetadata = &DataSourceWithConfigValidatorsAndGetSchemaAndMetadata{} + +// Declarative datasource.DataSourceWithGetSchema for unit testing. +type DataSourceWithConfigValidatorsAndGetSchemaAndMetadata struct { + *DataSource + + // DataSourceWithConfigValidators interface methods + ConfigValidatorsMethod func(context.Context) []datasource.ConfigValidator + + // DataSourceWithGetSchema interface methods + GetSchemaMethod func(context.Context) (tfsdk.Schema, diag.Diagnostics) + + // DataSourceWithMetadata interface methods + MetadataMethod func(context.Context, datasource.MetadataRequest, *datasource.MetadataResponse) +} + +// ConfigValidators satisfies the datasource.DataSourceWithConfigValidators interface. +func (d *DataSourceWithConfigValidatorsAndGetSchemaAndMetadata) ConfigValidators(ctx context.Context) []datasource.ConfigValidator { + if d.ConfigValidatorsMethod == nil { + return nil + } + + return d.ConfigValidatorsMethod(ctx) +} + +// GetSchema satisfies the datasource.DataSourceWithGetSchema interface. +func (d *DataSourceWithConfigValidatorsAndGetSchemaAndMetadata) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { + if d.GetSchemaMethod == nil { + return tfsdk.Schema{}, nil + } + + return d.GetSchemaMethod(ctx) +} + +// Metadata satisfies the datasource.DataSourceWithMetadata interface. +func (d *DataSourceWithConfigValidatorsAndGetSchemaAndMetadata) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + if d.MetadataMethod == nil { + return + } + + d.MetadataMethod(ctx, req, resp) +} + +var _ datasource.DataSource = &DataSourceWithGetSchemaAndMetadata{} +var _ datasource.DataSourceWithGetSchema = &DataSourceWithGetSchemaAndMetadata{} +var _ datasource.DataSourceWithMetadata = &DataSourceWithGetSchemaAndMetadata{} + +// Declarative datasource.DataSourceWithGetSchema for unit testing. +type DataSourceWithGetSchemaAndMetadata struct { + *DataSource + + // DataSourceWithGetSchema interface methods + GetSchemaMethod func(context.Context) (tfsdk.Schema, diag.Diagnostics) + + // DataSourceWithMetadata interface methods + MetadataMethod func(context.Context, datasource.MetadataRequest, *datasource.MetadataResponse) +} + +// GetSchema satisfies the datasource.DataSourceWithGetSchema interface. +func (d *DataSourceWithGetSchemaAndMetadata) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { + if d.GetSchemaMethod == nil { + return tfsdk.Schema{}, nil + } + + return d.GetSchemaMethod(ctx) +} + +// Metadata satisfies the datasource.DataSourceWithMetadata interface. +func (d *DataSourceWithGetSchemaAndMetadata) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + if d.MetadataMethod == nil { + return + } + + d.MetadataMethod(ctx, req, resp) +} + +var _ datasource.DataSource = &DataSourceWithGetSchemaAndMetadataAndValidateConfig{} +var _ datasource.DataSourceWithGetSchema = &DataSourceWithGetSchemaAndMetadataAndValidateConfig{} +var _ datasource.DataSourceWithMetadata = &DataSourceWithGetSchemaAndMetadataAndValidateConfig{} +var _ datasource.DataSourceWithValidateConfig = &DataSourceWithGetSchemaAndMetadataAndValidateConfig{} + +// Declarative datasource.DataSourceWithGetSchema for unit testing. +type DataSourceWithGetSchemaAndMetadataAndValidateConfig struct { + *DataSource + + // DataSourceWithGetSchema interface methods + GetSchemaMethod func(context.Context) (tfsdk.Schema, diag.Diagnostics) + + // DataSourceWithMetadata interface methods + MetadataMethod func(context.Context, datasource.MetadataRequest, *datasource.MetadataResponse) + + // DataSourceWithValidateConfig interface methods + ValidateConfigMethod func(context.Context, datasource.ValidateConfigRequest, *datasource.ValidateConfigResponse) +} + +// GetSchema satisfies the datasource.DataSourceWithGetSchema interface. +func (d *DataSourceWithGetSchemaAndMetadataAndValidateConfig) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { + if d.GetSchemaMethod == nil { + return tfsdk.Schema{}, nil + } + + return d.GetSchemaMethod(ctx) +} + +// Metadata satisfies the datasource.DataSourceWithMetadata interface. +func (d *DataSourceWithGetSchemaAndMetadataAndValidateConfig) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + if d.MetadataMethod == nil { + return + } + + d.MetadataMethod(ctx, req, resp) +} + +// ValidateConfig satisfies the datasource.DataSourceWithValidateConfig interface. +func (d *DataSourceWithGetSchemaAndMetadataAndValidateConfig) ValidateConfig(ctx context.Context, req datasource.ValidateConfigRequest, resp *datasource.ValidateConfigResponse) { + if d.ValidateConfigMethod == nil { + return + } + + d.ValidateConfigMethod(ctx, req, resp) +} diff --git a/internal/testing/testprovider/datasourcewithmetadata.go b/internal/testing/testprovider/datasourcewithmetadata.go new file mode 100644 index 000000000..c30f4493b --- /dev/null +++ b/internal/testing/testprovider/datasourcewithmetadata.go @@ -0,0 +1,27 @@ +package testprovider + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/datasource" +) + +var _ datasource.DataSource = &DataSourceWithMetadata{} +var _ datasource.DataSourceWithMetadata = &DataSourceWithMetadata{} + +// Declarative datasource.DataSourceWithMetadata for unit testing. +type DataSourceWithMetadata struct { + *DataSource + + // DataSourceWithMetadata interface methods + MetadataMethod func(context.Context, datasource.MetadataRequest, *datasource.MetadataResponse) +} + +// Metadata satisfies the datasource.DataSourceWithMetadata interface. +func (d *DataSourceWithMetadata) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + if d.MetadataMethod == nil { + return + } + + d.MetadataMethod(ctx, req, resp) +} diff --git a/internal/testing/testprovider/provider.go b/internal/testing/testprovider/provider.go index 4c9ce0751..09f52f96e 100644 --- a/internal/testing/testprovider/provider.go +++ b/internal/testing/testprovider/provider.go @@ -3,54 +3,64 @@ package testprovider import ( "context" + "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" ) var _ provider.Provider = &Provider{} +// Temporarily implement the new interfaces to ease testing transition +var _ provider.ProviderWithDataSources = &Provider{} +var _ provider.ProviderWithResources = &Provider{} + // Declarative provider.Provider for unit testing. type Provider struct { // Provider interface methods - ConfigureMethod func(context.Context, provider.ConfigureRequest, *provider.ConfigureResponse) - GetDataSourcesMethod func(context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) - GetResourcesMethod func(context.Context) (map[string]provider.ResourceType, diag.Diagnostics) - GetSchemaMethod func(context.Context) (tfsdk.Schema, diag.Diagnostics) + ConfigureMethod func(context.Context, provider.ConfigureRequest, *provider.ConfigureResponse) + GetSchemaMethod func(context.Context) (tfsdk.Schema, diag.Diagnostics) + + // ProviderWithDataSources interface methods + DataSourcesMethod func(context.Context) []func() datasource.DataSource + + // ProviderWithResources interface methods + ResourcesMethod func(context.Context) []func() resource.Resource } // GetSchema satisfies the provider.Provider interface. func (p *Provider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { - if p.ConfigureMethod == nil { + if p == nil || p.ConfigureMethod == nil { return } p.ConfigureMethod(ctx, req, resp) } -// GetDataSources satisfies the provider.Provider interface. -func (p *Provider) GetDataSources(ctx context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { - if p.GetDataSourcesMethod == nil { - return map[string]provider.DataSourceType{}, nil +// DataSources satisfies the provider.ProviderWithDataSources interface. +func (p *Provider) DataSources(ctx context.Context) []func() datasource.DataSource { + if p == nil || p.DataSourcesMethod == nil { + return nil } - return p.GetDataSourcesMethod(ctx) -} - -// GetResources satisfies the provider.Provider interface. -func (p *Provider) GetResources(ctx context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - if p.GetResourcesMethod == nil { - return map[string]provider.ResourceType{}, nil - } - - return p.GetResourcesMethod(ctx) + return p.DataSourcesMethod(ctx) } // GetSchema satisfies the provider.Provider interface. func (p *Provider) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { - if p.GetSchemaMethod == nil { + if p == nil || p.GetSchemaMethod == nil { return tfsdk.Schema{}, nil } return p.GetSchemaMethod(ctx) } + +// Resources satisfies the provider.ProviderWithResources interface. +func (p *Provider) Resources(ctx context.Context) []func() resource.Resource { + if p == nil || p.ResourcesMethod == nil { + return nil + } + + return p.ResourcesMethod(ctx) +} diff --git a/internal/testing/testprovider/providerwithgetdatasources.go b/internal/testing/testprovider/providerwithgetdatasources.go new file mode 100644 index 000000000..e43a94acf --- /dev/null +++ b/internal/testing/testprovider/providerwithgetdatasources.go @@ -0,0 +1,31 @@ +package testprovider + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/provider" +) + +var _ provider.Provider = &ProviderWithGetDataSources{} +var _ provider.ProviderWithGetDataSources = &ProviderWithGetDataSources{} //nolint:staticcheck // Internal usage + +// Declarative provider.ProviderWithGetDataSources for unit testing. +type ProviderWithGetDataSources struct { + *Provider + + // ProviderWithGetDataSources interface methods + //nolint:staticcheck // Internal implementation + GetDataSourcesMethod func(context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) +} + +// GetDataSources satisfies the provider.ProviderWithGetDataSources interface. +// +//nolint:staticcheck // Internal implementation +func (p *ProviderWithGetDataSources) GetDataSources(ctx context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { + if p.GetDataSourcesMethod == nil { + return nil, nil + } + + return p.GetDataSourcesMethod(ctx) +} diff --git a/internal/testing/testprovider/providerwithgetresources.go b/internal/testing/testprovider/providerwithgetresources.go new file mode 100644 index 000000000..2bbfbc2c0 --- /dev/null +++ b/internal/testing/testprovider/providerwithgetresources.go @@ -0,0 +1,31 @@ +package testprovider + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/provider" +) + +var _ provider.Provider = &ProviderWithGetResources{} +var _ provider.ProviderWithGetResources = &ProviderWithGetResources{} //nolint:staticcheck // Internal usage + +// Declarative provider.ProviderWithGetResources for unit testing. +type ProviderWithGetResources struct { + *Provider + + // ProviderWithGetResources interface methods + //nolint:staticcheck // Internal implementation + GetResourcesMethod func(context.Context) (map[string]provider.ResourceType, diag.Diagnostics) +} + +// GetResources satisfies the provider.ProviderWithGetResources interface. +// +//nolint:staticcheck // Internal implementation +func (p *ProviderWithGetResources) GetResources(ctx context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { + if p.GetResourcesMethod == nil { + return nil, nil + } + + return p.GetResourcesMethod(ctx) +} diff --git a/internal/testing/testprovider/providerwithmetadata.go b/internal/testing/testprovider/providerwithmetadata.go new file mode 100644 index 000000000..5aaf6fa31 --- /dev/null +++ b/internal/testing/testprovider/providerwithmetadata.go @@ -0,0 +1,27 @@ +package testprovider + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/provider" +) + +var _ provider.Provider = &ProviderWithMetadata{} +var _ provider.ProviderWithMetadata = &ProviderWithMetadata{} + +// Declarative provider.ProviderWithMetadata for unit testing. +type ProviderWithMetadata struct { + *Provider + + // ProviderWithMetadata interface methods + MetadataMethod func(context.Context, provider.MetadataRequest, *provider.MetadataResponse) +} + +// Metadata satisfies the provider.ProviderWithMetadata interface. +func (p *ProviderWithMetadata) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) { + if p.MetadataMethod == nil { + return + } + + p.MetadataMethod(ctx, req, resp) +} diff --git a/internal/testing/testprovider/resourcetype.go b/internal/testing/testprovider/resourcetype.go index fdc1a76f7..0e477621f 100644 --- a/internal/testing/testprovider/resourcetype.go +++ b/internal/testing/testprovider/resourcetype.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/tfsdk" ) -var _ provider.ResourceType = &ResourceType{} +var _ provider.ResourceType = &ResourceType{} //nolint:staticcheck // Internal implementation // Declarative provider.ResourceType for unit testing. type ResourceType struct { diff --git a/internal/testing/testprovider/resourcewithconfigure.go b/internal/testing/testprovider/resourcewithconfigure.go new file mode 100644 index 000000000..4f396fbfa --- /dev/null +++ b/internal/testing/testprovider/resourcewithconfigure.go @@ -0,0 +1,27 @@ +package testprovider + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +var _ resource.Resource = &ResourceWithConfigure{} +var _ resource.ResourceWithConfigure = &ResourceWithConfigure{} + +// Declarative resource.ResourceWithConfigure for unit testing. +type ResourceWithConfigure struct { + *Resource + + // ResourceWithConfigure interface methods + ConfigureMethod func(context.Context, resource.ConfigureRequest, *resource.ConfigureResponse) +} + +// Configure satisfies the resource.ResourceWithConfigure interface. +func (r *ResourceWithConfigure) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if r.ConfigureMethod == nil { + return + } + + r.ConfigureMethod(ctx, req, resp) +} diff --git a/internal/testing/testprovider/resourcewithconfigureandimportstate.go b/internal/testing/testprovider/resourcewithconfigureandimportstate.go new file mode 100644 index 000000000..b783e2d82 --- /dev/null +++ b/internal/testing/testprovider/resourcewithconfigureandimportstate.go @@ -0,0 +1,40 @@ +package testprovider + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +var _ resource.Resource = &ResourceWithConfigureAndImportState{} +var _ resource.ResourceWithConfigure = &ResourceWithConfigureAndImportState{} +var _ resource.ResourceWithImportState = &ResourceWithConfigureAndImportState{} + +// Declarative resource.ResourceWithConfigureAndImportState for unit testing. +type ResourceWithConfigureAndImportState struct { + *Resource + + // ResourceWithConfigureAndImportState interface methods + ConfigureMethod func(context.Context, resource.ConfigureRequest, *resource.ConfigureResponse) + + // ResourceWithImportState interface methods + ImportStateMethod func(context.Context, resource.ImportStateRequest, *resource.ImportStateResponse) +} + +// Configure satisfies the resource.ResourceWithConfigureAndImportState interface. +func (r *ResourceWithConfigureAndImportState) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if r.ConfigureMethod == nil { + return + } + + r.ConfigureMethod(ctx, req, resp) +} + +// ImportState satisfies the resource.ResourceWithImportState interface. +func (r *ResourceWithConfigureAndImportState) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + if r.ImportStateMethod == nil { + return + } + + r.ImportStateMethod(ctx, req, resp) +} diff --git a/internal/testing/testprovider/resourcewithconfigureandmodifyplan.go b/internal/testing/testprovider/resourcewithconfigureandmodifyplan.go new file mode 100644 index 000000000..169a4dd07 --- /dev/null +++ b/internal/testing/testprovider/resourcewithconfigureandmodifyplan.go @@ -0,0 +1,40 @@ +package testprovider + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +var _ resource.Resource = &ResourceWithConfigureAndModifyPlan{} +var _ resource.ResourceWithConfigure = &ResourceWithConfigureAndModifyPlan{} +var _ resource.ResourceWithModifyPlan = &ResourceWithConfigureAndModifyPlan{} + +// Declarative resource.ResourceWithConfigureAndModifyPlan for unit testing. +type ResourceWithConfigureAndModifyPlan struct { + *Resource + + // ResourceWithConfigureAndModifyPlan interface methods + ConfigureMethod func(context.Context, resource.ConfigureRequest, *resource.ConfigureResponse) + + // ResourceWithModifyPlan interface methods + ModifyPlanMethod func(context.Context, resource.ModifyPlanRequest, *resource.ModifyPlanResponse) +} + +// Configure satisfies the resource.ResourceWithConfigureAndModifyPlan interface. +func (r *ResourceWithConfigureAndModifyPlan) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if r.ConfigureMethod == nil { + return + } + + r.ConfigureMethod(ctx, req, resp) +} + +// ModifyPlan satisfies the resource.ResourceWithModifyPlan interface. +func (r *ResourceWithConfigureAndModifyPlan) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + if r.ModifyPlanMethod == nil { + return + } + + r.ModifyPlanMethod(ctx, req, resp) +} diff --git a/internal/testing/testprovider/resourcewithconfigureandupgradestate.go b/internal/testing/testprovider/resourcewithconfigureandupgradestate.go new file mode 100644 index 000000000..88a235704 --- /dev/null +++ b/internal/testing/testprovider/resourcewithconfigureandupgradestate.go @@ -0,0 +1,40 @@ +package testprovider + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +var _ resource.Resource = &ResourceWithConfigureAndUpgradeState{} +var _ resource.ResourceWithConfigure = &ResourceWithConfigureAndUpgradeState{} +var _ resource.ResourceWithUpgradeState = &ResourceWithConfigureAndUpgradeState{} + +// Declarative resource.ResourceWithConfigureAndUpgradeState for unit testing. +type ResourceWithConfigureAndUpgradeState struct { + *Resource + + // ResourceWithConfigureAndUpgradeState interface methods + ConfigureMethod func(context.Context, resource.ConfigureRequest, *resource.ConfigureResponse) + + // ResourceWithUpgradeState interface methods + UpgradeStateMethod func(context.Context) map[int64]resource.StateUpgrader +} + +// Configure satisfies the resource.ResourceWithConfigureAndUpgradeState interface. +func (r *ResourceWithConfigureAndUpgradeState) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if r.ConfigureMethod == nil { + return + } + + r.ConfigureMethod(ctx, req, resp) +} + +// UpgradeState satisfies the resource.ResourceWithUpgradeState interface. +func (r *ResourceWithConfigureAndUpgradeState) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { + if r.UpgradeStateMethod == nil { + return nil + } + + return r.UpgradeStateMethod(ctx) +} diff --git a/internal/testing/testprovider/resourcewithgetschema.go b/internal/testing/testprovider/resourcewithgetschema.go new file mode 100644 index 000000000..930fe57cf --- /dev/null +++ b/internal/testing/testprovider/resourcewithgetschema.go @@ -0,0 +1,29 @@ +package testprovider + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" +) + +var _ resource.Resource = &ResourceWithGetSchema{} +var _ resource.ResourceWithGetSchema = &ResourceWithGetSchema{} + +// Declarative resource.ResourceWithGetSchema for unit testing. +type ResourceWithGetSchema struct { + *Resource + + // ResourceWithGetSchema interface methods + GetSchemaMethod func(context.Context) (tfsdk.Schema, diag.Diagnostics) +} + +// GetSchema satisfies the resource.ResourceWithGetSchema interface. +func (r *ResourceWithGetSchema) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { + if r.GetSchemaMethod == nil { + return tfsdk.Schema{}, nil + } + + return r.GetSchemaMethod(ctx) +} diff --git a/internal/testing/testprovider/resourcewithgetschema_temp.go b/internal/testing/testprovider/resourcewithgetschema_temp.go new file mode 100644 index 000000000..ac38d7c2b --- /dev/null +++ b/internal/testing/testprovider/resourcewithgetschema_temp.go @@ -0,0 +1,281 @@ +package testprovider + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" +) + +// This file contains temporary types until GetSchema and Metadata are required +// in Resource. + +var _ resource.Resource = &ResourceWithConfigValidatorsAndGetSchemaAndMetadata{} +var _ resource.ResourceWithConfigValidators = &ResourceWithConfigValidatorsAndGetSchemaAndMetadata{} +var _ resource.ResourceWithGetSchema = &ResourceWithConfigValidatorsAndGetSchemaAndMetadata{} +var _ resource.ResourceWithMetadata = &ResourceWithConfigValidatorsAndGetSchemaAndMetadata{} + +// Declarative resource.ResourceWithGetSchema for unit testing. This type is +// temporary until GetSchema and Metadata are required in Resource. +type ResourceWithConfigValidatorsAndGetSchemaAndMetadata struct { + *Resource + + // ResourceWithConfigValidators interface methods + ConfigValidatorsMethod func(context.Context) []resource.ConfigValidator + + // ResourceWithGetSchema interface methods + GetSchemaMethod func(context.Context) (tfsdk.Schema, diag.Diagnostics) + + // ResourceWithMetadata interface methods + MetadataMethod func(context.Context, resource.MetadataRequest, *resource.MetadataResponse) +} + +// ConfigValidators satisfies the resource.ResourceWithConfigValidators interface. +func (r *ResourceWithConfigValidatorsAndGetSchemaAndMetadata) ConfigValidators(ctx context.Context) []resource.ConfigValidator { + if r.ConfigValidatorsMethod == nil { + return nil + } + + return r.ConfigValidatorsMethod(ctx) +} + +// GetSchema satisfies the resource.ResourceWithGetSchema interface. +func (r *ResourceWithConfigValidatorsAndGetSchemaAndMetadata) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { + if r.GetSchemaMethod == nil { + return tfsdk.Schema{}, nil + } + + return r.GetSchemaMethod(ctx) +} + +// Metadata satisfies the resource.ResourceWithMetadata interface. +func (r *ResourceWithConfigValidatorsAndGetSchemaAndMetadata) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + if r.MetadataMethod == nil { + return + } + + r.MetadataMethod(ctx, req, resp) +} + +var _ resource.Resource = &ResourceWithGetSchemaAndMetadata{} +var _ resource.ResourceWithGetSchema = &ResourceWithGetSchemaAndMetadata{} +var _ resource.ResourceWithMetadata = &ResourceWithGetSchemaAndMetadata{} + +// Declarative resource.ResourceWithGetSchema for unit testing. This type is +// temporary until GetSchema and Metadata are required in Resource. +type ResourceWithGetSchemaAndMetadata struct { + *Resource + + // ResourceWithGetSchema interface methods + GetSchemaMethod func(context.Context) (tfsdk.Schema, diag.Diagnostics) + + // ResourceWithMetadata interface methods + MetadataMethod func(context.Context, resource.MetadataRequest, *resource.MetadataResponse) +} + +// GetSchema satisfies the resource.ResourceWithGetSchema interface. +func (r *ResourceWithGetSchemaAndMetadata) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { + if r.GetSchemaMethod == nil { + return tfsdk.Schema{}, nil + } + + return r.GetSchemaMethod(ctx) +} + +// Metadata satisfies the resource.ResourceWithMetadata interface. +func (r *ResourceWithGetSchemaAndMetadata) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + if r.MetadataMethod == nil { + return + } + + r.MetadataMethod(ctx, req, resp) +} + +var _ resource.Resource = &ResourceWithGetSchemaAndImportStateAndMetadata{} +var _ resource.ResourceWithGetSchema = &ResourceWithGetSchemaAndImportStateAndMetadata{} +var _ resource.ResourceWithImportState = &ResourceWithGetSchemaAndImportStateAndMetadata{} +var _ resource.ResourceWithMetadata = &ResourceWithGetSchemaAndImportStateAndMetadata{} + +// Declarative resource.ResourceWithGetSchema for unit testing. This type is +// temporary until GetSchema and Metadata are required in Resource. +type ResourceWithGetSchemaAndImportStateAndMetadata struct { + *Resource + + // ResourceWithGetSchema interface methods + GetSchemaMethod func(context.Context) (tfsdk.Schema, diag.Diagnostics) + + // ResourceWithImportState interface methods + ImportStateMethod func(context.Context, resource.ImportStateRequest, *resource.ImportStateResponse) + + // ResourceWithMetadata interface methods + MetadataMethod func(context.Context, resource.MetadataRequest, *resource.MetadataResponse) +} + +// GetSchema satisfies the resource.ResourceWithGetSchema interface. +func (r *ResourceWithGetSchemaAndImportStateAndMetadata) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { + if r.GetSchemaMethod == nil { + return tfsdk.Schema{}, nil + } + + return r.GetSchemaMethod(ctx) +} + +// ImportState satisfies the resource.ResourceWithImportState interface. +func (r *ResourceWithGetSchemaAndImportStateAndMetadata) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + if r.ImportStateMethod == nil { + return + } + + r.ImportStateMethod(ctx, req, resp) +} + +// Metadata satisfies the resource.ResourceWithMetadata interface. +func (r *ResourceWithGetSchemaAndImportStateAndMetadata) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + if r.MetadataMethod == nil { + return + } + + r.MetadataMethod(ctx, req, resp) +} + +var _ resource.Resource = &ResourceWithGetSchemaAndModifyPlanAndMetadata{} +var _ resource.ResourceWithGetSchema = &ResourceWithGetSchemaAndModifyPlanAndMetadata{} +var _ resource.ResourceWithModifyPlan = &ResourceWithGetSchemaAndModifyPlanAndMetadata{} +var _ resource.ResourceWithMetadata = &ResourceWithGetSchemaAndModifyPlanAndMetadata{} + +// Declarative resource.ResourceWithGetSchema for unit testing. This type is +// temporary until GetSchema and Metadata are required in Resource. +type ResourceWithGetSchemaAndModifyPlanAndMetadata struct { + *Resource + + // ResourceWithGetSchema interface methods + GetSchemaMethod func(context.Context) (tfsdk.Schema, diag.Diagnostics) + + // ResourceWithModifyPlan interface methods + ModifyPlanMethod func(context.Context, resource.ModifyPlanRequest, *resource.ModifyPlanResponse) + + // ResourceWithMetadata interface methods + MetadataMethod func(context.Context, resource.MetadataRequest, *resource.MetadataResponse) +} + +// GetSchema satisfies the resource.ResourceWithGetSchema interface. +func (r *ResourceWithGetSchemaAndModifyPlanAndMetadata) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { + if r.GetSchemaMethod == nil { + return tfsdk.Schema{}, nil + } + + return r.GetSchemaMethod(ctx) +} + +// ModifyPlan satisfies the resource.ResourceWithModifyPlan interface. +func (r *ResourceWithGetSchemaAndModifyPlanAndMetadata) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + if r.ModifyPlanMethod == nil { + return + } + + r.ModifyPlanMethod(ctx, req, resp) +} + +// Metadata satisfies the resource.ResourceWithMetadata interface. +func (r *ResourceWithGetSchemaAndModifyPlanAndMetadata) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + if r.MetadataMethod == nil { + return + } + + r.MetadataMethod(ctx, req, resp) +} + +var _ resource.Resource = &ResourceWithGetSchemaAndMetadataAndUpgradeState{} +var _ resource.ResourceWithGetSchema = &ResourceWithGetSchemaAndMetadataAndUpgradeState{} +var _ resource.ResourceWithMetadata = &ResourceWithGetSchemaAndMetadataAndUpgradeState{} +var _ resource.ResourceWithUpgradeState = &ResourceWithGetSchemaAndMetadataAndUpgradeState{} + +// Declarative resource.ResourceWithGetSchema for unit testing. This type is +// temporary until GetSchema and Metadata are required in Resource. +type ResourceWithGetSchemaAndMetadataAndUpgradeState struct { + *Resource + + // ResourceWithGetSchema interface methods + GetSchemaMethod func(context.Context) (tfsdk.Schema, diag.Diagnostics) + + // ResourceWithMetadata interface methods + MetadataMethod func(context.Context, resource.MetadataRequest, *resource.MetadataResponse) + + // ResourceWithUpgradeState interface methods + UpgradeStateMethod func(context.Context) map[int64]resource.StateUpgrader +} + +// GetSchema satisfies the resource.ResourceWithGetSchema interface. +func (r *ResourceWithGetSchemaAndMetadataAndUpgradeState) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { + if r.GetSchemaMethod == nil { + return tfsdk.Schema{}, nil + } + + return r.GetSchemaMethod(ctx) +} + +// Metadata satisfies the resource.ResourceWithMetadata interface. +func (r *ResourceWithGetSchemaAndMetadataAndUpgradeState) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + if r.MetadataMethod == nil { + return + } + + r.MetadataMethod(ctx, req, resp) +} + +// UpgradeState satisfies the resource.ResourceWithUpgradeState interface. +func (r *ResourceWithGetSchemaAndMetadataAndUpgradeState) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { + if r.UpgradeStateMethod == nil { + return nil + } + + return r.UpgradeStateMethod(ctx) +} + +var _ resource.Resource = &ResourceWithGetSchemaAndMetadataAndValidateConfig{} +var _ resource.ResourceWithGetSchema = &ResourceWithGetSchemaAndMetadataAndValidateConfig{} +var _ resource.ResourceWithMetadata = &ResourceWithGetSchemaAndMetadataAndValidateConfig{} +var _ resource.ResourceWithValidateConfig = &ResourceWithGetSchemaAndMetadataAndValidateConfig{} + +// Declarative resource.ResourceWithGetSchema for unit testing. This type is +// temporary until GetSchema and Metadata are required in Resource. +type ResourceWithGetSchemaAndMetadataAndValidateConfig struct { + *Resource + + // ResourceWithGetSchema interface methods + GetSchemaMethod func(context.Context) (tfsdk.Schema, diag.Diagnostics) + + // ResourceWithMetadata interface methods + MetadataMethod func(context.Context, resource.MetadataRequest, *resource.MetadataResponse) + + // ResourceWithValidateConfig interface methods + ValidateConfigMethod func(context.Context, resource.ValidateConfigRequest, *resource.ValidateConfigResponse) +} + +// GetSchema satisfies the resource.ResourceWithGetSchema interface. +func (r *ResourceWithGetSchemaAndMetadataAndValidateConfig) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { + if r.GetSchemaMethod == nil { + return tfsdk.Schema{}, nil + } + + return r.GetSchemaMethod(ctx) +} + +// Metadata satisfies the resource.ResourceWithMetadata interface. +func (r *ResourceWithGetSchemaAndMetadataAndValidateConfig) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + if r.MetadataMethod == nil { + return + } + + r.MetadataMethod(ctx, req, resp) +} + +// ValidateConfig satisfies the resource.ResourceWithValidateConfig interface. +func (r *ResourceWithGetSchemaAndMetadataAndValidateConfig) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { + if r.ValidateConfigMethod == nil { + return + } + + r.ValidateConfigMethod(ctx, req, resp) +} diff --git a/internal/testing/testprovider/resourcewithmetadata.go b/internal/testing/testprovider/resourcewithmetadata.go new file mode 100644 index 000000000..83dcd5a3a --- /dev/null +++ b/internal/testing/testprovider/resourcewithmetadata.go @@ -0,0 +1,27 @@ +package testprovider + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +var _ resource.Resource = &ResourceWithMetadata{} +var _ resource.ResourceWithMetadata = &ResourceWithMetadata{} + +// Declarative resource.ResourceWithMetadata for unit testing. +type ResourceWithMetadata struct { + *Resource + + // ResourceWithMetadata interface methods + MetadataMethod func(context.Context, resource.MetadataRequest, *resource.MetadataResponse) +} + +// Metadata satisfies the resource.ResourceWithMetadata interface. +func (r *ResourceWithMetadata) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + if r.MetadataMethod == nil { + return + } + + r.MetadataMethod(ctx, req, resp) +} diff --git a/provider/configure.go b/provider/configure.go index 29a41271a..d489c6209 100644 --- a/provider/configure.go +++ b/provider/configure.go @@ -28,8 +28,18 @@ type ConfigureRequest struct { // an argument to the provider's Configure function, in which the provider // should set values on the ConfigureResponse as appropriate. type ConfigureResponse struct { + // DataSourceData is provider-defined data, clients, etc. that is passed + // to [datasource.ConfigureRequest.ProviderData] for each DataSource type + // that implements the Configure method. + DataSourceData any + // Diagnostics report errors or warnings related to configuring the // provider. An empty slice indicates success, with no warnings or // errors generated. Diagnostics diag.Diagnostics + + // ResourceData is provider-defined data, clients, etc. that is passed + // to [resource.ConfigureRequest.ProviderData] for each Resource type + // that implements the Configure method. + ResourceData any } diff --git a/provider/data_source_type.go b/provider/data_source_type.go index e43193fd8..9ee76f986 100644 --- a/provider/data_source_type.go +++ b/provider/data_source_type.go @@ -11,6 +11,10 @@ import ( // A DataSourceType is a type of data source. For each type of data source this // provider supports, it should define a type implementing DataSourceType and // return an instance of it in the map returned by Provider.GetDataSources. +// +// Deprecated: Migrate to datasource.DataSource implementation Configure, +// GetSchema, and Metadata methods. Migrate the provider.Provider +// implementation from the GetDataSources method to the DataSources method. type DataSourceType interface { // GetSchema returns the schema for this data source. GetSchema(context.Context) (tfsdk.Schema, diag.Diagnostics) diff --git a/provider/metadata.go b/provider/metadata.go new file mode 100644 index 000000000..cbab966f7 --- /dev/null +++ b/provider/metadata.go @@ -0,0 +1,21 @@ +package provider + +// MetadataRequest represents a request for the Provider to return its type +// name. An instance of this request struct is supplied as an argument to the +// Provider type Metadata method. +type MetadataRequest struct{} + +// MetadataResponse represents a response to a MetadataRequest. An +// instance of this response struct is supplied as an argument to the +// Provider type Metadata method. +type MetadataResponse struct { + // TypeName should be the provider type. For example, examplecloud, if + // the intended resource or data source types are examplecloud_thing, etc. + TypeName string + + // Version should be the provider version, such as 1.2.3. + // + // This is not connected to any framework functionality currently, but may + // be in the future. + Version string +} diff --git a/provider/provider.go b/provider/provider.go index 9ba14f617..11d7f1a64 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -3,7 +3,9 @@ package provider import ( "context" + "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/tfsdk" ) @@ -11,6 +13,10 @@ import ( // // Providers can optionally implement these additional concepts: // +// - Resources: ProviderWithResources or (deprecated) +// ProviderWithGetResources. +// - Data Sources: ProviderWithDataSources or (deprecated) +// ProviderWithGetDataSources. // - Validation: Schema-based via tfsdk.Attribute or entire configuration // via ProviderWithConfigValidators or ProviderWithValidateConfig. // - Meta Schema: ProviderWithMetaSchema @@ -27,15 +33,43 @@ type Provider interface { // API client, which should be stored on the struct implementing the // Provider interface. Configure(context.Context, ConfigureRequest, *ConfigureResponse) +} - // GetResources returns a mapping of resource names to type - // implementations. +// ProviderWithConfigValidators is an interface type that extends Provider to include declarative validations. +// +// Declaring validation using this methodology simplifies implementation of +// reusable functionality. These also include descriptions, which can be used +// for automating documentation. +// +// Validation will include ConfigValidators and ValidateConfig, if both are +// implemented, in addition to any Attribute or Type validation. +type ProviderWithConfigValidators interface { + Provider + + // ConfigValidators returns a list of functions which will all be performed during validation. + ConfigValidators(context.Context) []ConfigValidator +} + +// ProviderWithDataSources is an interface type that extends Provider to +// include data source implementations. +type ProviderWithDataSources interface { + Provider + + // DataSources returns a slice of functions to instantiate each DataSource + // implementation. // - // Conventionally, resource names should each include a prefix of the - // provider name and an underscore. For example, a provider named - // "examplecloud" with resources "thing" and "widget" should use - // "examplecloud_thing" and "examplecloud_widget" as resource names. - GetResources(context.Context) (map[string]ResourceType, diag.Diagnostics) + // The data source type name is determined by the DataSource implementing + // the Metadata method. All data sources must have unique names. + DataSources(context.Context) []func() datasource.DataSource +} + +// ProviderWithGetDataSources is an interface type that extends Provider to +// include the previously required GetDataSources method. +// +// Deprecated: This will be removed in a future release. Use the DataSources +// method instead. +type ProviderWithGetDataSources interface { + Provider // GetDataSources returns a mapping of data source name to types // implementations. @@ -44,22 +78,46 @@ type Provider interface { // provider name and an underscore. For example, a provider named // "examplecloud" with data sources "thing" and "widget" should use // "examplecloud_thing" and "examplecloud_widget" as data source names. + // + // Deprecated: This will be removed in a future release. Use the + // DataSources method instead. GetDataSources(context.Context) (map[string]DataSourceType, diag.Diagnostics) } -// ProviderWithConfigValidators is an interface type that extends Provider to include declarative validations. +// ProviderWithGetResources is an interface type that extends Provider to +// include the previously required GetResources method. // -// Declaring validation using this methodology simplifies implementation of -// reusable functionality. These also include descriptions, which can be used -// for automating documentation. +// Deprecated: This will be removed in a future release. Use the Resources +// method instead. +type ProviderWithGetResources interface { + Provider + + // GetResources returns a mapping of resource names to type + // implementations. + // + // Conventionally, resource names should each include a prefix of the + // provider name and an underscore. For example, a provider named + // "examplecloud" with resources "thing" and "widget" should use + // "examplecloud_thing" and "examplecloud_widget" as resource names. + // + // Deprecated: This will be removed in a future release. Use the Resources + // method instead. + GetResources(context.Context) (map[string]ResourceType, diag.Diagnostics) +} + +// ProviderWithMetadata is an interface type that extends Provider to +// return its type name, such as examplecloud, and other +// metadata, such as version. // -// Validation will include ConfigValidators and ValidateConfig, if both are -// implemented, in addition to any Attribute or Type validation. -type ProviderWithConfigValidators interface { +// Implementing this method will populate the +// [datasource.MetadataRequest.ProviderTypeName] and +// [resource.MetadataRequest.ProviderTypeName] fields automatically. +type ProviderWithMetadata interface { Provider - // ConfigValidators returns a list of functions which will all be performed during validation. - ConfigValidators(context.Context) []ConfigValidator + // 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. @@ -73,6 +131,19 @@ type ProviderWithMetaSchema interface { GetMetaSchema(context.Context) (tfsdk.Schema, diag.Diagnostics) } +// ProviderWithResources is an interface type that extends Provider to +// include data source implementations. +type ProviderWithResources interface { + Provider + + // Resources returns a slice of functions to instantiate each Resource + // implementation. + // + // The resource type name is determined by the Resource implementing + // the Metadata method. All resources must have unique names. + Resources(context.Context) []func() resource.Resource +} + // ProviderWithValidateConfig is an interface type that extends Provider to include imperative validation. // // Declaring validation using this methodology simplifies one-off diff --git a/provider/resource_type.go b/provider/resource_type.go index b6a7fb01b..93c61e5d0 100644 --- a/provider/resource_type.go +++ b/provider/resource_type.go @@ -11,6 +11,10 @@ import ( // A ResourceType is a type of resource. For each type of resource this provider // supports, it should define a type implementing ResourceType and return an // instance of it in the map returned by Provider.GetResources. +// +// Deprecated: Migrate to resource.Resource implementation Configure, +// GetSchema, and Metadata methods. Migrate the provider.Provider +// implementation from the GetResources method to the Resources method. type ResourceType interface { // GetSchema returns the schema for this resource. GetSchema(context.Context) (tfsdk.Schema, diag.Diagnostics) diff --git a/resource/configure.go b/resource/configure.go new file mode 100644 index 000000000..1cb349b34 --- /dev/null +++ b/resource/configure.go @@ -0,0 +1,31 @@ +package resource + +import ( + "github.com/hashicorp/terraform-plugin-framework/diag" +) + +// ConfigureRequest represents a request for the provider to configure a +// resource, i.e., set provider-level data or clients. An instance of this +// request struct is supplied as an argument to the Resource type Configure +// method. +type ConfigureRequest struct { + // ProviderData is the data set in the + // [provider.ConfigureResponse.ResourceData] field. This data is + // provider-specifc and therefore can contain any necessary remote system + // clients, custom provider data, or anything else pertinent to the + // functionality of the Resource. + // + // This data is only set after the ConfigureProvider RPC has been called + // by Terraform. + ProviderData any +} + +// ConfigureResponse represents a response to a ConfigureRequest. An +// instance of this response struct is supplied as an argument to the +// Resource type Configure method. +type ConfigureResponse struct { + // Diagnostics report errors or warnings related to configuring of the + // Datasource. An empty slice indicates a successful operation with no + // warnings or errors generated. + Diagnostics diag.Diagnostics +} diff --git a/resource/doc.go b/resource/doc.go index 2aecf47c6..1d8077e07 100644 --- a/resource/doc.go +++ b/resource/doc.go @@ -9,14 +9,13 @@ // // Resources are saved into the Terraform state and can be referenced by other // parts of a configuration. Resources are defined by a resource type/name, -// such as "example_thing", a schema representing the structure and data types -// of configuration, plan, and state, and lifecycle logic. +// such as "examplecloud_thing", a schema representing the structure and data +// types of configuration, plan, and state, and lifecycle logic. // // The main starting point for implementations in this package is the // Resource type which represents an instance of a resource type that has -// its own configuration, plan, state, and lifecycle logic. A Resource is -// instantiated from a provider.ResourceType type NewResource method, which -// also defines the resource schema. The provider.ResourceType types are -// referenced by a provider.Provider type GetResources method, which enables -// the resource for practitioner and testing usage. +// its own configuration, plan, state, and lifecycle logic. The +// [resource.Resource] implementations are referenced by the +// [provider.Provider] type Resources method, which enables the resource +// practitioner and testing usage. package resource diff --git a/resource/metadata.go b/resource/metadata.go new file mode 100644 index 000000000..683292113 --- /dev/null +++ b/resource/metadata.go @@ -0,0 +1,21 @@ +package resource + +// MetadataRequest represents a request for the Resource to return metadata, +// such as its type name. An instance of this request struct is supplied as +// an argument to the Resource type Metadata method. +type MetadataRequest struct { + // ProviderTypeName is the string returned from + // [provider.MetadataResponse.TypeName], if the Provider type implements + // the Metadata method. This string should prefix the Resource type name + // with an underscore in the response. + ProviderTypeName string +} + +// MetadataResponse represents a response to a MetadataRequest. An +// instance of this response struct is supplied as an argument to the +// Resource type Metadata method. +type MetadataResponse struct { + // TypeName should be the full resource type, including the provider + // type prefix and an underscore. For example, examplecloud_thing. + TypeName string +} diff --git a/resource/resource.go b/resource/resource.go index d303a696f..c8aea6ddd 100644 --- a/resource/resource.go +++ b/resource/resource.go @@ -2,6 +2,9 @@ package resource import ( "context" + + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" ) // Resource represents an instance of a managed resource type. This is the core @@ -9,6 +12,7 @@ import ( // // Resources can optionally implement these additional concepts: // +// - Configure: Include provider-level data or clients. // - Import: ResourceWithImportState // - Validation: Schema-based via tfsdk.Attribute or entire configuration // via ResourceWithConfigValidators or ResourceWithValidateConfig. @@ -43,6 +47,22 @@ type Resource interface { Delete(context.Context, DeleteRequest, *DeleteResponse) } +// ResourceWithConfigure is an interface type that extends Resource to +// include a method which the framework will automatically call so provider +// developers have the opportunity to setup any necessary provider-level data +// or clients in the Resource type. +// +// This method is intended to replace the provider.ResourceType type +// NewResource method in a future release. +type ResourceWithConfigure interface { + Resource + + // Configure enables provider-level data or clients to be set in the + // provider-defined DataSource type. It is separately executed for each + // ReadDataSource RPC. + Configure(context.Context, ConfigureRequest, *ConfigureResponse) +} + // ResourceWithConfigValidators is an interface type that extends Resource to include declarative validations. // // Declaring validation using this methodology simplifies implmentation of @@ -58,6 +78,16 @@ type ResourceWithConfigValidators interface { ConfigValidators(context.Context) []ConfigValidator } +// ResourceWithGetSchema is an interface type that extends Resource to +// return its schema definition. +// +// This method will be required in the Resource interface in a future +// release. +type ResourceWithGetSchema interface { + // GetSchema returns the schema for this data source. + GetSchema(context.Context) (tfsdk.Schema, diag.Diagnostics) +} + // Optional interface on top of Resource that enables provider control over // the ImportResourceState RPC. This RPC is called by Terraform when the // `terraform import` command is executed. Afterwards, the ReadResource RPC @@ -100,6 +130,20 @@ type ResourceWithModifyPlan interface { ModifyPlan(context.Context, ModifyPlanRequest, *ModifyPlanResponse) } +// ResourceWithMetadata is an interface type that extends Resource to +// return metadata, such as its resource type name. For example, if the +// provider is named examplecloud and the resource manages a thing, this +// should return examplecloud_thing. +// +// This method will be required in the Resource interface a future release. +type ResourceWithMetadata interface { + Resource + + // Metadata should return the full name of the resource, such as + // examplecloud_thing. + Metadata(context.Context, MetadataRequest, *MetadataResponse) +} + // Optional interface on top of Resource that enables provider control over // the UpgradeResourceState RPC. This RPC is automatically called by Terraform // when the current Schema type Version field is greater than the stored state. diff --git a/website/data/plugin-framework-nav-data.json b/website/data/plugin-framework-nav-data.json index bc78b352d..87c86564f 100644 --- a/website/data/plugin-framework-nav-data.json +++ b/website/data/plugin-framework-nav-data.json @@ -25,6 +25,10 @@ "title": "Overview", "path": "resources" }, + { + "title": "Configure Clients", + "path": "resources/configure" + }, { "title": "Import", "path": "resources/import" @@ -45,7 +49,16 @@ }, { "title": "Data Sources", - "path": "data-sources" + "routes": [ + { + "title": "Overview", + "path": "data-sources" + }, + { + "title": "Configure Clients", + "path": "data-sources/configure" + } + ] }, { "title": "Schemas", diff --git a/website/docs/plugin/framework/acctests.mdx b/website/docs/plugin/framework/acctests.mdx index 622fea34e..afe3a2049 100644 --- a/website/docs/plugin/framework/acctests.mdx +++ b/website/docs/plugin/framework/acctests.mdx @@ -24,18 +24,11 @@ Use the [`providerserver.NewProtocol6WithError`](https://pkg.go.dev/github.com/h ```go resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error) { // newProvider is an example function that returns a provider.Provider - "example_provider": providerserver.NewProtocol6WithError(newProvider()), - }, - CheckDestroy: testAccCheckExampleResourceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccExampleResource, - Check: testAccCheckExampleResourceExists, - }, + "examplecloud": providerserver.NewProtocol6WithError(newProvider()), }, + Steps: []resource.TestStep{/* ... */}, }) ``` @@ -45,18 +38,11 @@ Use the [`providerserver.NewProtocol5WithError`](https://pkg.go.dev/github.com/h ```go resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, ProtoV5ProviderFactories: map[string]func() (tfprotov5.ProviderServer, error) { // newProvider is an example function that returns a provider.Provider - "example_provider": providerserver.NewProtocol5WithError(newProvider()), - }, - CheckDestroy: testAccCheckExampleResourceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccExampleResource, - Check: testAccCheckExampleResourceExists, - }, + "examplecloud": providerserver.NewProtocol5WithError(newProvider()), }, + Steps: []resource.TestStep{/* ... */}, }) ``` @@ -73,10 +59,10 @@ testing_new.go:53: no "id" found in attributes To avoid this, add a root level `id` attribute to resource and data source schemas. Ensure the attribute value is appropriately [written to state](/plugin/framework/writing-state). Conventionally, `id` is a computed attribute that contains the identifier for the resource. -For example, in the `GetSchema` method implementation of a [`provider.DataSourceType`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#DataSourceType) or [`provider.ResourceType`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#ResourceType): +For example, in the `GetSchema` method implementation of a [`datasource.DataSource`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/datasource#DataSource) or [`resource.Resource`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#Resource): ```go -func (t exampleResourceType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { +func (r *ThingResource) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { return tfsdk.Schema{ // ... potentially other schema configuration ... Attributes: map[string]tfsdk.Attribute{ diff --git a/website/docs/plugin/framework/data-sources.mdx b/website/docs/plugin/framework/data-sources.mdx deleted file mode 100644 index 9a14b8661..000000000 --- a/website/docs/plugin/framework/data-sources.mdx +++ /dev/null @@ -1,101 +0,0 @@ ---- -page_title: 'Plugin Development - Framework: Data Sources' -description: >- - How to build data sources in the provider development framework. Data sources - allow Terraform to reference external data. ---- - -# Data Sources - -[Data sources](/language/data-sources) are an abstraction that allow Terraform to reference external data. Unlike with resources, Terraform does not manage data sources and makes no attempt to modify the API. - -Providers have data sources that tell Terraform how to request external data and how to convert the response into a format that practitioners can interpolate. To create data sources for your provider, you need to define both the data source archetype and actions on specific data source instances. - -## Define Data Source Archetype - -Implement the [`provider.DataSourceType` -interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#DataSourceType) -for every type of data source you want to support, such as disk images, compute -instance groups, access policies, etc. It allows you to describe the data -source archetype, which is the functionality related to all instances of that -data source type. `DataSourceType` has the following methods. - -### GetSchema - -`GetSchema` returns a [schema](/plugin/framework/schemas) describing -what fields are available in the data source's configuration and state. - -### NewDataSource - -`NewDataSource` returns a new instance of that data source type. It needs to instantiate a new [`datasource.DataSource` -implementation](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/datasource#DataSource) -that expects to operate on data with the structure defined in `GetSchema`. - -The `NewDataSource` method is passed a [`provider.Provider` -implementation](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#Provider). -This is the [provider type](/plugin/framework/providers) after its -`Configure` method was called. The `NewDataSource` method can type-assert on -this and inject it into the `DataSource`, allowing the `DataSource` to have -strongly-typed access to the configured API client or other provider -configuration data. - -
- -**Example** - -```go -type computeImageDataSourceType struct{} - -func (c computeImageDataSourceType) GetSchema(_ context.Context) (tfsdk.Schema, - diag.Diagnostics) { - return tfsdk.Schema{ - Attributes: map[string]tfsdk.Attribute{ - "name": { - Type: types.StringType, - Required: true, - }, - }, - }, nil -} - -func (c computeImageDataSourceType) NewDataSource(_ context.Context, - p provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return computeImageDataSource{ - client: p.(*provider).client, - }, nil -} -``` - -## Define Data Source - -Data sources are scoped to a single instance of the data source type. They modify that specific data source in the state, given that data source's config values. They do this through their `Read` method. - -### Read - -`Read` updates Terraform's state to reflect the API data described in the configuration. There is no plan or state to work with in `Read`. Data sources should [retrieve the data they need](/plugin/framework/accessing-values) from the configuration included in the [`datasource.ReadRequest`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/datasource#ReadRequest). -They can then use the configured API client injected into the data source by the -data source type's `NewDataSource` method, and [write the results to the state](/plugin/framework/writing-state). - -Terraform does not manage data sources, so there is no plan to follow and the provider can set any value in state. "Drift" describes instances when the API's state has deviated from the source of truth defined in the configuration file. Drift doesn't apply to data sources because Terraform is not the source of truth for these values. - -## Add Data Source to Provider - -To make new data sources available to practitioners, add them to the -`GetDataSources` method on the [provider](/plugin/framework/providers). The key must be the name of -the data source, including the provider prefix, and the value must be an -instance of the data source type. - -**Example** - -```go -func (p *provider) GetDataSources(_ context.Context) (map[string]provider.DataSourceType, - diag.Diagnostics) { - return map[string]provider.DataSourceType{ - "example_compute_image": computeImageDataSourceType{}, - }, nil -} -``` - -## Further Data Source Capabilities - -- [Validation](/plugin/framework/validation) helps practitioners understand the required syntax, types, and acceptable values for your data source. diff --git a/website/docs/plugin/framework/data-sources/configure.mdx b/website/docs/plugin/framework/data-sources/configure.mdx new file mode 100644 index 000000000..2cd749cc3 --- /dev/null +++ b/website/docs/plugin/framework/data-sources/configure.mdx @@ -0,0 +1,96 @@ +--- +page_title: 'Plugin Development - Framework: Configure Data Sources' +description: >- + How to configure data sources with provider data or clients in the provider development framework. +--- + +# Configure Data Sources + +[Data sources](/plugin/framework/data-sources) may require provider-level data or remote system clients to operate correctly. The framework supports the ability to configure this data and/or clients once within the provider, then pass that information to data sources by adding the `Configure` method. + +## Prepare Provider Configure Method + +Implement the [`provider.ConfigureResponse.DataSourceData` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#ConfigureResponse.DataSourceData) in the [`Provider` interface `Configure` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#Provider.Configure). This value can be set to any type, whether an existing client or vendor SDK type, a provider-defined custom type, or the provider implementation itself. It is recommended to use pointer types so that data sources can determine if this value was configured before attempting to use it. + +In this example, the Go standard library [`net/http.Client`](https://pkg.go.dev/net/http#Client) is configured in the provider, and made available for data sources: + +```go +// With the provider.Provider implementation +func (p *ExampleCloudProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { + resp.DataSourceData = &http.Client{/* ... */} +} +``` + +In this example, the code defines an `ExampleClient` type that is made available for data sources: + +```go +type ExampleClient struct { + /* ... */ +} + +// With the provider.Provider implementation +func (p *ExampleCloudProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { + resp.DataSourceData = &ExampleClient{/* ... */} +} +``` + +In this example, the `ExampleCloudProvider` type itself is made available for data sources: + +```go +// With the provider.Provider implementation +type ExampleCloudProvider struct { + /* ... */ +} + +func (p *ExampleCloudProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { + resp.DataSourceData = p +} +``` + +## Define Data Source Configure Method + +Implement the [`datasource.DataSourceWithConfigure` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/datasource#DataSourceWithConfigure) which receives the provider configured data from the [`Provider` interface `Configure` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#Provider.Configure) and saves it into the [`datasource.DataSource` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/datasource#DataSource) implementation. + +In this example, the provider configured the Go standard library [`net/http.Client`](https://pkg.go.dev/net/http#Client) which the data source uses during `Read`: + +```go +// With the datasource.DataSource implementation +type ThingDataSource struct { + client *http.Client +} + +func (d *ThingDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + 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 + } + + d.client = client +} + +func (d *ThingDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + // Prevent panic if the provider has not been configured. + if d.client == nil { + resp.Diagnostics.AddError( + "Unconfigured HTTP Client", + "Expected configured HTTP client. Please report this issue to the provider developers.", + ) + + return + } + + httpResp, err := d.client.Get("https://example.com") + /* ... */ +} +``` diff --git a/website/docs/plugin/framework/data-sources/index.mdx b/website/docs/plugin/framework/data-sources/index.mdx new file mode 100644 index 000000000..ea3a88bc7 --- /dev/null +++ b/website/docs/plugin/framework/data-sources/index.mdx @@ -0,0 +1,146 @@ +--- +page_title: 'Plugin Development - Framework: Data Sources' +description: >- + How to build data sources in the provider development framework. Data sources + allow Terraform to reference external data. +--- + +# Data Sources + +[Data sources](/language/data-sources) are an abstraction that allow Terraform to reference external data. Unlike [managed resources](/language/resources), Terraform does not manage the lifecycle of the resource or data. Data sources are intended to have no side-effects. + +This page describes the basic implementation details required for supporting a data source within the provider. Further documentation is available for deeper data source concepts: + +- [Configure](/plugin/framework/data-sources/configure) data sources with provider-level data types or clients. +- [Validate](/plugin/framework/validation) practitioner configuration against acceptable values. + +## Define Data Source Type + +Implement the [`datasource.DataSource` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/datasource#DataSource). Each of the methods is described in more detail below. + +In this example, a data source named `examplecloud_thing` with hardcoded behavior is defined: + +```go +// Ensure the implementation satisfies the desired interfaces. +var _ datasource.DataSource = &ThingDataSource{} + +type ThingDataSource struct {} + +type ThingDataSourceModel struct { + ExampleAttribute types.String `tfsdk:"example_attribute"` + ID types.String `tfsdk:"id"` +} + +func (d *ThingDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "examplecloud_thing" +} + +func (d *ThingDataSource) GetSchema(ctx context.Context) (fwschema.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "example_attribute": { + Required: true, + Type: types.StringType, + }, + "id": { + Computed: true, + Type: types.StringType, + }, + }, + }, nil +} + +func (d *ThingDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data ThingDataSourceModel + + // Read Terraform configuration data into the model + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + // Typically data sources will make external calls, however this example + // hardcodes setting the id attribute to a specific value for brevity. + data.ID = types.String{Value: "example-id"} + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} +``` + +### Metadata Method + +The [`datasource.DataSourceWithMetadata` interface `Metadata` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/datasource#DataSourceWithMetadata.Metadata) defines the data source name as it would appear in Terraform configurations. This name should include the provider type prefix, an underscore, then the data source specific name. For example, a provider named `examplecloud` and a data source that reads "thing" resources would be named `examplecloud_thing`. Ensure the [Add Data Source To Provider](#add-data-source-to-provider) documentation is followed so the data source becomes part of the provider implementation, and therefore available to practitioners. + +In this example, the data source name in an `examplecloud` provider that reads "thing" resources is hardcoded to `examplecloud_thing`: + +```go +// With the datasource.DataSource implementation +func (d *ThingDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "examplecloud_thing" +} +``` + +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). + +In this example, the provider defines the `examplecloud` name for itself, and the data source is named `examplecloud_thing`: + +```go +// With the provider.Provider implementation +func (p *ExampleCloudProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) { + resp.TypeName = "examplecloud" +} + +// With the datasource.DataSource implementation +func (d *ThingDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_thing" +} +``` + +### GetSchema Method + +The [`datasource.DataSourceWithGetSchema` interface `GetSchema` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/datasource#DataSourceWithGetSchema.GetSchema) defines a [schema](/plugin/framework/schemas) describing what data is available in the data source's configuration and state. + +### Read Method + +The [`datasource.DataSource` interface `Read` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/datasource#DataSource.Read) defines how the data source updates Terraform's state to reflect the retrieved data. There is no plan or prior state to work with in `Read` requests, only configuration. + +Implement the `Read` method by: + +1. [Accessing configuration data](/plugin/framework/accessing-values) from the [`datasource.ReadRequest.Config` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/datasource#ReadRequest.Config). +1. Retriving any additional data, such as remote system information. +1. [Writing state data](/plugin/framework/writing-state) into the [`datasource.ReadResponse.State` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/datasource#ReadResponse.State). + +If the logic needs to return [warning or error diagnostics](/plugin/framework/diagnostics), they can added into the [`datasource.ReadResponse.Diagnostics` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/datasource#ReadResponse.Diagnostics). + +## Add Data Source to Provider + +Data sources become available to practitioners when they are included in the [provider](/plugin/framework/providers) implementation via the [`provider.ProviderWithDataSources` interface `DataSources` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#ProviderWithDataSources.DataSources). + +In this example, the `ThingDataSource` type, which implements the `datasource.DataSource` interface, is added to the provider implementation: + +```go +// With the provider.Provider implementation +func (p *ExampleCloudProvider) DataSources(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + func() datasource.DataSource { + return &ThingDataSource{}, + }, + } +} +``` + +To simplify provider implementations, a named function can be created with the data source implementation. + +In this example, the `ThingDataSource` code includes an additional `NewThingDataSource` function, which simplifies the provider implementation: + +```go +// With the provider.Provider implementation +func (p *ExampleCloudProvider) DataSources(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + NewThingDataSource, + } +} + +// With the datasource.DataSource implementation +func NewThingDataSource() datasource.DataSource { + return &ThingDataSource{} +} +``` diff --git a/website/docs/plugin/framework/providers.mdx b/website/docs/plugin/framework/providers.mdx index c3359372d..469ae4d57 100644 --- a/website/docs/plugin/framework/providers.mdx +++ b/website/docs/plugin/framework/providers.mdx @@ -10,32 +10,31 @@ description: >- Providers are Terraform plugins that define [resources](/plugin/framework/resources) and [data sources](/plugin/framework/data-sources) for practitioners to use. Providers are wrapped by a [provider server](/plugin/framework/provider-servers) for interacting with Terraform. -## Implement Provider Interface +This page describes the basic implementation details required for defining a provider. Further documentation is available for deeper provider concepts: -Any type that fills the [provider.Provider interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#Provider) can be a provider. The provider interface has four required methods: `GetSchema`, `Configure`, `GetResources`, and `GetDataSources`. We recommend that you define a `struct` type to fill this interface. +- [Configure data sources](/plugin/framework/data-sources/configure) with provider-level data types or clients. +- [Configure resources](/plugin/framework/resources/configure) with provider-level data types or clients. +- [Validate](/plugin/framework/validation) practitioner configuration against acceptable values. -An example provider implementation with a field storing an example API client: +## Define Provider Type + +Implement the [provider.Provider interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#Provider). Each of the methods described in more detail below. + +In this example, a provider implementation is scaffolded: ```go // Ensure the implementation satisfies the provider.Provider interface. -var _ provider.Provider = &exampleProvider{} - -// exampleProvider implements the provider.Provider interface. This implementation -// will be passed to data sources and resources as the provider.Provider parameter -// in each NewDataSource and NewResource method call respectively. -type exampleProvider struct{ - // Typically fields including API clients or configuration necessary for - // resource and data source operations. For example: - Client exampleApiClient +var _ provider.Provider = &ExampleCloudProvider{} - // version is an example field that can be set with an actual provider +type ExampleCloudProvider struct{ + // Version is an example field that can be set with an actual provider // version on release, "dev" when the provider is built and ran locally, // and "test" when running acceptance testing. Version string } // GetSchema satisfies the provider.Provider interface for exampleProvider. -func (p *exampleProvider) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { +func (p *ExampleCloudProvider) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { return tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ // Provider specific implementation. @@ -43,23 +42,23 @@ func (p *exampleProvider) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Dia }, nil } -// Configure satisfies the provider.Provider interface for exampleProvider. -func (p *exampleProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { +// Configure satisfies the provider.Provider interface for ExampleCloudProvider. +func (p *ExampleCloudProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { // Provider specific implementation. } -// GetDataSources satisfies the provider.Provider interface for exampleProvider. -func (p *exampleProvider) GetDataSources(ctx context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { - return map[string]provider.DataSourceType{ +// DataSources satisfies the provider.Provider interface for ExampleCloudProvider. +func (p *ExampleCloudProvider) DataSources(ctx context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ // Provider specific implementation - }, nil + } } -// GetResources satisfies the provider.Provider interface for exampleProvider. -func (p *exampleProvider) GetResources(ctx context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ +// Resources satisfies the provider.Provider interface for ExampleCloudProvider. +func (p *ExampleCloudProvider) Resources(ctx context.Context) []func() resource.Resource { + return []func() resource.Resource{ // Provider specific implementation - }, nil + } } ``` @@ -68,47 +67,122 @@ Conventionally, many providers also create a helper function named `New` which c ```go func New(version string) func() provider.Provider { return func() provider.Provider { - return &exampleProvider{ + return &ExampleCloudProvider{ Version: version, } } } ``` -### GetSchema +### GetSchema Method -`GetSchema` returns a -[schema](/plugin/framework/schemas) that describes the provider's -configuration block. 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. +The [`provider.Provider` interface `GetSchema` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#Provider.GetSchema) 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. -```tf -provider "example" { - endpoint = "https://example.test/" - api_token = "v3rYs3cr3tt0k3n" +In this example, a sample configuration and schema definition are provided: + +```go +// Example Terraform configuration: +// +// provider "examplecloud" { +// api_token = "v3rYs3cr3tt0k3n" +// endpoint = "https://example.com/" +// } + +func (p *ExampleCloudProvider) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "api_token": { + Optional: true, + Type: types.StringType, + }, + "endpoint": { + Optional: true, + Type: types.StringType, + }, + }, + }, nil } ``` -Even if the provider does not want to accept practitioner configuration, it must return -an empty schema. +If the provider does not accept practitioner Terraform configuration, it must return an empty schema (`tfsdk.Schema{}`). + +### Configure Method + +The [`provider.Provider` interface `Configure` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#Provider.Configure) handles the configuration of any provider-level data or clients. These configuration values may be from the practitioner Terraform configuration, environment variables, or other means such as reading vendor-specific configuration files. + +This is the only chance the provider has to configure provider-level data or clients, so they need to be persisted if other data source or resource logic will need to reference them. Refer to the [Configure Data Sources](/plugin/framework/data-sources/configure) and [Configure Resources](/plugin/framework/resources/configure) pages for additional implementation details. + +If the logic needs to return [warning or error diagnostics](/plugin/framework/diagnostics), they can added into the [`provider.ConfigureResponse.Diagnostics` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#ConfigureResponse.Diagnostics). + +In this example, the provider API token and endpoint are configured via environment variable or Terraform configuration: + +```go +type ExampleCloudProvider struct {} + +type ExampleCloudProviderModel struct { + ApiToken types.String `tfsdk:"api_token"` + Endpoint types.String `tfsdk:"endpoint"` +} + +func (p *ExampleCloudProvider) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { + return tfsdk.Schema{ + Attributes: map[string]tfsdk.Attribute{ + "api_token": { + Optional: true, + Type: types.StringType, + }, + "endpoint": { + Optional: true, + Type: types.StringType, + }, + }, + }, nil +} + +func (p *ExampleCloudProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { + // Check environment variables + apiToken := os.Getenv("EXAMPLECLOUD_API_TOKEN") + endpoint := os.Getenv("EXAMPLECLOUD_ENDPOINT") + + var data ExampleCloudProviderModel + + // Read configuration data into model + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + // Check configuration data, which should take precedence over + // environment variable data, if found. + if data.ApiToken.Value != "" { + apiToken = data.ApiToken.Value + } -The schema is meant to be immutable. It should not change at runtime, and -should consistently return the same value. + if data.Endpoint.Value != "" { + endpoint = data.Endpoint.Value + } -### Configure + if apiToken == "" { + resp.Diagnostics.AddError( + "Missing API Token Configuration", + "While configuring the provider, the API token was not found in "+ + "the EXAMPLECLOUD_API_TOKEN environment variable or provider "+ + "configuration block api_token attribute.", + ) + // Not returning early allows the logic to collect all errors. + } -`Configure` handles and stores the -values the practitioner entered in the provider's configuration block. This -can mean creating the API client, storing the data on the type that -implements the provider interface, or otherwise handling the values. This is -the only time those values will be made available to the provider, so they -need to be persisted if the provider will need to reference them from within -a resource or data source. This is why we recommend using a struct -to represent the provider, as it can hold multiple values in a strongly-typed -way. + if endpoint == "" { + resp.Diagnostics.AddError( + "Missing Endpoint Configuration", + "While configuring the provider, the endpoint was not found in "+ + "the EXAMPLECLOUD_ENDPOINT environment variable or provider "+ + "configuration block endpoint attribute.", + ) + // Not returning early allows the logic to collect all errors. + } + + // Create data/clients and persist to resp.DataSourceData and + // resp.ResourceData as appropriate. +} +``` #### Unknown Values @@ -118,18 +192,16 @@ For example, if a practitioner interpolates a resource's unknown value into the that value may show up as unknown depending on how the graph executes: ```tf -resource "example_foo" "bar" { - id = 123 -} +resource "random_string" "example" {} -provider "example" { - endpoint = "https://example.test/" - api_token = example_foo.bar.name +provider "examplecloud" { + api_token = random_string.example.result + endpoint = "https://example.com/" } ``` -In the example above, `example_foo.bar.name` is a read-only field on -`example_foo.bar` that won't be set until after `example_foo.bar` has been +In the example above, `random_string.example.result` is a read-only field on +`random_string.example` that won't be set until after `random_string.example` has been applied. So the `Configure` method for the provider may report that the value is unknown. You can choose how your provider handles this. If some resources or data sources can be used without knowing that value, it may @@ -139,26 +211,114 @@ to use it. If resources and data sources can't provide any functionality without knowing that value, it's often better to [return an error](/plugin/framework/diagnostics), which will halt the apply. -### GetResources +### Resources -`GetResources` returns a map of [resource -types](/plugin/framework/resources). The keys of the -map entries must be the name of the resource as it would appear in the -configuration, including the provider prefix. +The [`provider.ProviderWithResources` interface `Resources` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#ProviderWithResources.Resources) returns a slice of [resources](/plugin/framework/resources). Each element in the slice is a function to create a new `resource.Resource` so data is not inadvertently shared across multiple, disjointed resource instance operations unless explicitly coded. Information such as the resource type name is managed by the `resource.Resource` implementation. -The list of resources is meant to be immutable. It should not change at -runtime, and should consistently return the same values. +In this example, the provider implements a single resource: -### GetDataSources +```go +// With the provider.Provider implementation +func (p *ExampleCloudProvider) Resources(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + NewThingResource, + } +} -`GetDataSources` returns a map of [data -source types](/plugin/framework/data-sources). The -keys of the map entries must be the name of the data source as it would appear -in the configuration, including the provider prefix. +// With the resource.Resource implementation +func NewThingResource() resource.Resource { + return &ThingResource{} +} + +type ThingResource struct {} +``` + +Use Go slice techniques to include large numbers of resources outside the provider `Resources` method code. + +In this example, the provider codebase implements multiple "services" which group their own resources: + +```go +// With the provider.Provider implementation +func (p *ExampleCloudProvider) Resources(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + servicex.Resources..., + servicey.Resources..., + } +} + +// With the servicex implementation +package servicex + +var Resources = []func() resource.Resource { + NewThingResource, + NewWidgetResource, +} + +func NewThingResource() resource.Resource { + return & +} -The list of data sources is meant to be immutable. It should not change at -runtime, and should consistently return the same values. +type ThingResource struct {} -## Further Provider Capabilities +func NewWidgetResource() resource.Resource { + return &WidgetResource{} +} + +type WidgetResource struct {} +``` -- [Validation](/plugin/framework/validation) helps practitioners understand the required syntax, types, and acceptable values for your provider. +### DataSources + +The [`provider.ProviderWithDataSources` interface `DataSources` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#ProviderWithDataSources.DataSources) returns a slice of [data sources](/plugin/framework/data-sources). Each element in the slice is a function to create a new `datasource.DataSource` so data is not inadvertently shared across multiple, disjointed datasource instance operations unless explicitly coded. Information such as the datasource type name is managed by the `datasource.DataSource` implementation. + +In this example, the provider implements a single data source: + +```go +// With the provider.Provider implementation +func (p *ExampleCloudProvider) DataSources(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + NewThingDataSource, + } +} + +// With the datasource.DataSource implementation +func NewThingDataSource() datasource.DataSource { + return &ThingDataSource{} +} + +type ThingDataSource struct {} +``` + +Use Go slice techniques to include large numbers of data sources outside the provider `DataSources` method code. + +In this example, the provider codebase implements multiple "services" which group their own datasources: + +```go +// With the provider.Provider implementation +func (p *ExampleCloudProvider) DataSources(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + servicex.DataSources..., + servicey.DataSources..., + } +} + +// With the servicex implementation +package servicex + +var DataSources = []func() datasource.DataSource { + NewThingDataSource, + NewWidgetDataSource, +} + +func NewThingDataSource() datasource.DataSource { + return & +} + +type ThingDataSource struct {} + +func NewWidgetDataSource() datasource.DataSource { + return &WidgetDataSource{} +} + +type WidgetDataSource struct {} +``` diff --git a/website/docs/plugin/framework/resources/configure.mdx b/website/docs/plugin/framework/resources/configure.mdx new file mode 100644 index 000000000..0ad464ff8 --- /dev/null +++ b/website/docs/plugin/framework/resources/configure.mdx @@ -0,0 +1,96 @@ +--- +page_title: 'Plugin Development - Framework: Configure Resources' +description: >- + How to configure resources with provider data or clients in the provider development framework. +--- + +# Configure Resources + +[Resources](/plugin/framework/resources) may require provider-level data or remote system clients to operate correctly. The framework supports the ability to configure this data and/or clients once within the provider, then pass that information to resources by adding the `Configure` method. + +## Prepare Provider Configure Method + +Implement the [`provider.ConfigureResponse.ResourceData` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#ConfigureResponse.ResourceData) in the [`Provider` interface `Configure` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#Provider.Configure). This value can be set to any type, whether an existing client or vendor SDK type, a provider-defined custom type, or the provider implementation itself. It is recommended to use pointer types so that resources can determine if this value was configured before attempting to use it. + +In this example, the Go standard library [`net/http.Client`](https://pkg.go.dev/net/http#Client) is configured in the provider, and made available for resources: + +```go +// With the provider.Provider implementation +func (p *ExampleCloudProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { + resp.ResourceData = &http.Client{/* ... */} +} +``` + +In this example, the code defines an `ExampleClient` type that is made available for resources: + +```go +type ExampleClient struct { + /* ... */ +} + +// With the provider.Provider implementation +func (p *ExampleCloudProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { + resp.ResourceData = &ExampleClient{/* ... */} +} +``` + +In this example, the `ExampleCloudProvider` type itself is made available for resources: + +```go +// With the provider.Provider implementation +type ExampleCloudProvider struct { + /* ... */ +} + +func (p *ExampleCloudProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { + resp.ResourceData = p +} +``` + +## Define Resource Configure Method + +Implement the [`resource.ResourceWithConfigure` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ResourceWithConfigure) which receives the provider configured data from the [`Provider` interface `Configure` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#Provider.Configure) and saves it into the [`resource.Resource` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#Resource) implementation. + +In this example, the provider configured the Go standard library [`net/http.Client`](https://pkg.go.dev/net/http#Client) which the resource uses during `Read`: + +```go +// With the resource.Resource implementation +type ThingResource struct { + client *http.Client +} + +func (r *ThingResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + 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 + } + + r.client = client +} + +func (r *ThingResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + // Prevent panic if the provider has not been configured. + if r.client == nil { + resp.Diagnostics.AddError( + "Unconfigured HTTP Client", + "Expected configured HTTP client. Please report this issue to the provider developers.", + ) + + return + } + + httpResp, err := r.client.Get("https://example.com") + /* ... */ +} +``` diff --git a/website/docs/plugin/framework/resources/import.mdx b/website/docs/plugin/framework/resources/import.mdx index 30a3bd192..f8a084c35 100644 --- a/website/docs/plugin/framework/resources/import.mdx +++ b/website/docs/plugin/framework/resources/import.mdx @@ -8,30 +8,39 @@ description: >- Practitioners can use the [`terraform import` command](/cli/commands/import) to let Terraform begin managing existing infrastructure resources. Resources can implement the `ImportState` method, which must either specify enough Terraform state for the `Read` method to refresh [`resource.Resource`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#Resource) or return an error. -## Single Attribute +## Define Resource ImportState Method -When the `Read` method requires a single attribute to refresh, use the [`resource.ImportStatePassthroughID` function](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ImportStatePassthroughID) to write the import identifier argument for `terraform import`. +The [`resource.ResourceWithImportState` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ResourceWithImportState) on the [`resource.Resource` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#Resource) implementation will enable practitioner support for importing an existing resource. -In the following example, the `terraform import` command passes the import identifier to the `id` attribute in Terraform state. +Implement the `ImportState` method by: + +1. Accessing the import identifier from the [`resource.ImportStateRequest.ID` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ImportStateRequest) +1. [Writing state data](/plugin/framework/writing-state) into the [`resource.ImportStateResponse.State` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ImportStateResponse.State). + +In this example, the resource state has the `id` attribute set to the value passed into the [`terraform import` command](/cli/commands/import) using the [`resource.ImportStatePassthroughID` function](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ImportStatePassthroughID): ```go -func (r exampleResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *ThingResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) } ``` -## Multiple Attributes +### Multiple Attributes + +When the `Read` method requires multiple attributes to refresh, you must write custom logic in the `ImportState` method. -When the `Read` method requires multiple attributes to refresh, you must write custom logic in the `ImportState` method. Specifically, the implementation must: +Implement the `ImportState` method by: -1. Use the import identifier from the [`resource.ImportStateRequest`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ImportStateRequest). -1. Perform the custom logic. -1. [Set state data](/plugin/framework/writing-state) in the [`resource.ImportStateResponse`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ImportStateResponse). +1. Accessing the import identifier from the [`resource.ImportStateRequest.ID` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ImportStateRequest) +1. Performing the custom logic. +1. [Writing state data](/plugin/framework/writing-state) into the [`resource.ImportStateResponse.State` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ImportStateResponse.State). -For example, if the `provider.ResourceType` implementation has the following `GetSchema` method: +The `terraform import` command will need to accept the multiple attribute values as a single import identifier string. A typical convention is to use a separator character, such as a comma (`,`), between the values. The `ImportState` method will then need to parse the import identifier string into the multiple separate values and save them appropriately into the Terraform state. + +In this example, the resource requires two attributes to refresh state and accepts them as an import identifier of `attr_one,attr_two`: ```go -func (t exampleResourceType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { +func (r *ThingResource) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { return tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "attr_one": { @@ -42,16 +51,12 @@ func (t exampleResourceType) GetSchema(ctx context.Context) (tfsdk.Schema, diag. Type: types.StringType, Required: true, }, - // ... potentially other Attributes ... + /* ... */ }, }, nil } -``` - -Along with a `resource.Resource` implementation with the following `Read` method: -```go -func (r exampleResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { +func (r *ThingResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var attrOne, attrTwo string resp.Diagnostics.Append(req.State.GetAttribute(ctx, path.Root("attr_one"), &attrOne)...) @@ -63,14 +68,8 @@ func (r exampleResource) Read(ctx context.Context, req resource.ReadRequest, res // API call using attrOne and attrTwo } -``` - -The `terraform import` command will need to accept both attribute values as a single import identifier string. A typical convention is to use a separator character, such as a comma (`,`), between the values. The `ImportState` method will then need to parse the import identifier string into the two separate values and save them appropriately into the Terraform state. -You could define the `ImportState` method using a comma-separated value as follows: - -```go -func (r exampleResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *ThingResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, ",") if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { diff --git a/website/docs/plugin/framework/resources/index.mdx b/website/docs/plugin/framework/resources/index.mdx index 29149f3df..75e6b9a14 100644 --- a/website/docs/plugin/framework/resources/index.mdx +++ b/website/docs/plugin/framework/resources/index.mdx @@ -13,68 +13,144 @@ description: >- - needs only one API call to update or return its state. - can be be created, read, updated, and deleted. -Providers act as a translation layer between Terraform and an API, offering one or more resources for practitioners to define in a configuration. To create resources for your provider, you need to define both the resource archetype and actions on specific resource instances. +This page describes the basic implementation details required for supporting a resource within the provider. Further documentation is available for deeper resource concepts: -## Define Resource Archetype +- [Configure](/plugin/framework/resources/configure) resources with provider-level data types or clients. +- [Import state](/plugin/framework/resources/import) so practitioners can bring existing resources under Terraform lifecycle management. +- [Manage private state](/plugin/framework/resources/private-state) to store additional data in resource state that is not shown in plans. +- [Modify plans](/plugin/framework/resources/plan-modification) to enrich the output for expected resource behaviors during changes, such as including default values for missing configurations or marking a resource for replacement if an in-place update cannot occur. +- [Upgrade state](/plugin/framework/resources/state-upgrade) to transparently update state data outside plans. +- [Validate](/plugin/framework/validation) practitioner configuration against acceptable values. -Implement the [`provider.ResourceType` -interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#ResourceType) for every type of -resource you want to support: compute instances, disks, access policies, etc. It -allows you to describe the resource archetype, which is the functionality related to all instances of that resource type in the configuration, state, plan, and API. `ResourceType` has the following methods: +## Define Resource Type -### GetSchema +Implement the [`resource.Resource` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#Resource). Each of the methods is described in more detail below. -`GetSchema` returns a [schema](/plugin/framework/schemas) describing what fields are available in the resource's configuration and state. +In this example, a resource named `examplecloud_thing` with sample lifecycle management behavior is defined: -### NewResource - -`NewResource` returns a new instance of that resource type. It instantiates a new [`resource.Resource` implementation](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#Resource) -that expects to operate on data with the structure defined in `GetSchema`. It does not need to create the instance on the API. +```go +// Ensure the implementation satisfies the desired interfaces. +var _ resource.Resource = &ThingResource{} -The `NewResource` method is passed a [`provider.Provider` implementation](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#Provider). -This is the [provider type](/plugin/framework/providers) after its -`Configure` method was called. The `NewResource` method can type-assert on this -and inject it into the `Resource`, allowing the `Resource` to have -strongly-typed access to the configured API client or other provider -configuration data. +type ThingResource struct {} -
-**Example** +type ThingResourceModel struct { + ExampleAttribute types.String `tfsdk:"example_attribute"` + ID types.String `tfsdk:"id"` +} -```go -type computeInstanceResourceType struct{} +func (r *ThingResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "examplecloud_thing" +} -func (c computeInstanceResourceType) GetSchema(_ context.Context) (tfsdk.Schema, - diag.Diagnostics) { +func (r *ThingResource) GetSchema(ctx context.Context) (fwschema.Schema, diag.Diagnostics) { return tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ - "name": { - Type: types.StringType, + "example_attribute": { Required: true, + Type: types.StringType, + }, + "id": { + Computed: true, + Type: types.StringType, }, }, }, nil } -func (c computeInstanceResourceType) NewResource(_ context.Context, - p provider.Provider) (resource.Resource, diag.Diagnostics) { - return computeInstanceResource{ - client: p.(*provider).client, - }, nil +func (r *ThingResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data ThingResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + // Typically resources will make external calls, however this example + // hardcodes setting the id attribute to a specific value for brevity. + data.ID = types.String{Value: "example-id"} + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *ThingResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data ThingResourceModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + // Typically resources will make external calls, however this example + // omits any refreshed data updates for brevity. + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *ThingResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data ThingResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + // Typically resources will make external calls, however this example + // omits any update calls for brevity. + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *ThingResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data ThingResourceModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + // Typically resources will make external calls, however this example + // omits any deletion calls for brevity. +} +``` + +### Metadata Method + +The [`resource.ResourceWithMetadata` interface `Metadata` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ResourceWithMetadata.Metadata) defines the resource name as it would appear in Terraform configurations. This name should include the provider type prefix, an underscore, then the resource specific name. For example, a provider named `examplecloud` and a resource that reads "thing" resources would be named `examplecloud_thing`. Ensure the [Add Data Source To Provider](#add-data-source-to-provider) documentation is followed so the resource becomes part of the provider implementation, and therefore available to practitioners. + +In this example, the resource name in an `examplecloud` provider that reads "thing" resources is hardcoded to `examplecloud_thing`: + +```go +// With the resource.Resource implementation +func (r *ThingResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "examplecloud_thing" +} +``` + +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). + +In this example, the provider defines the `examplecloud` name for itself, and the data source is named `examplecloud_thing`: + +```go +// With the provider.Provider implementation +func (p *ExampleCloudProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) { + resp.TypeName = "examplecloud" +} + +// With the resource.Resource implementation +func (d *ThingDataSource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_thing" } ``` -## Define Resources +### GetSchema Method -Resources are scoped to a single instance of a resource type. They modify a specific resource in the API and in the state, given that resource's configuration, state, and plan values. They do this through the following methods. +The [`resource.ResourceWithGetSchema` interface `GetSchema` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ResourceWithGetSchema.GetSchema) defines a [schema](/plugin/framework/schemas) describing what data is available in the resource's configuration, plan, and state. ### Create -`Create` makes the necessary API calls to create the resource and then persist that resource's data into the Terraform state. This is usually accomplished by: +The [`resource.Resource` interface `Create` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#Resource.Create) makes the necessary API calls to create the resource and then persist that resource's data into the Terraform state. + +Implement the `Create` method by: -1. [Reading the plan data](/plugin/framework/accessing-values) from the [`resource.CreateRequest`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#CreateRequest) -1. Using the configured API client injected into the resource by the resource type's `NewResource` method -1. [Writing to the state](/plugin/framework/writing-state). +1. [Accessing the data](/plugin/framework/accessing-values) from the [`resource.CreateRequest` type](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#CreateRequest). Most use cases should access the plan data in the [`resource.CreateRequest.Plan` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#CreateRequest.Plan). +1. Performing logic or external calls to create and/or run the resource. +1. [Writing state data](/plugin/framework/writing-state) into the [`resource.CreateResponse.State` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#CreateResponse.State). It is very important that every known value in the plan ends up in state as a byte-for-byte match, or Terraform will throw errors. The plan is the provider's @@ -83,13 +159,17 @@ contract with Terraform: the provider can only change values that are very important that every unknown value in the plan gets a known, concrete value when it's set in the state; the state can never hold any unknown values. +If the logic needs to return [warning or error diagnostics](/plugin/framework/diagnostics), they can added into the [`resource.CreateResponse.Diagnostics` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#CreateResponse.Diagnostics). Any errors will trigger Terraform to mark the resource as tainted for recreation on the next Terraform plan. + ### Read -`Read` updates Terraform's state to reflect the latest state of the resource in the API. +The [`resource.Resource` interface `Read` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#Resource.Read) makes the necessary calls to retrieve the latest resource state and then persist that updated state into the Terraform state. There is no plan or configuration data in `Read`. + +Implement the `Read` method by: -There is no plan or config to work with in `Read`. Resources should [retrieve the data they need](/plugin/framework/accessing-values) from the current state included in the [`resource.ReadRequest`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ReadRequest). They can then use the configured API client injected into the resource by the -resource type's `NewResource` method, and [write the results to the -state](/plugin/framework/writing-state). +1. [Accessing prior state data](/plugin/framework/accessing-values) from the [`resource.ReadRequest.State` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ReadRequest.State). +1. Retriving updated resource state, such as remote system information. +1. [Writing state data](/plugin/framework/writing-state) into the [`resource.ReadResponse.State` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ReadResponse.State). The provider can set any value in state, but you should be mindful of values that: @@ -105,14 +185,73 @@ The provider can set any value in state, but you should be mindful of values tha _existing_ value should always be maintained in state and should not be replaced with the new representation that the API is returning. +If the logic needs to return [warning or error diagnostics](/plugin/framework/diagnostics), they can added into the [`resource.ReadResponse.Diagnostics` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ReadResponse.Diagnostics). + +If the logic needs to signal that the resource no longer exists and should be recreated, call the [`RemoveResource` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/tfsdk#State.RemoveResource) on the [`resource.ReadResponse.State` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ReadResponse.State). + +In this example, the `Read` function catches a HTTP 404 Not Found status and returns early to signal resource recreation: + +```go +type ThingResource struct { + // client is configured via a Configure method, which is not shown in this + // example for brevity. Refer to the Configure Resources documentation for + // additional details for setting up resources with external clients. + client *http.Client +} + +func (r *ThingResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data ThingResourceModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + httpReq := http.NewRequestWithContext( + ctx, + http.MethodGet, + fmt.Sprintf("http://example.com/thing/%s", data.ID), + nil, + ) + + httpResp, err := d.client.Do(httpReq) + defer httpResp.Body.Close() + + if err != nil { + resp.Diagnostics.AddError( + "Unable to Refresh Resource", + "An unexpected error occurred while attempting to refresh resource state. "+ + "Please retry the operation or report this issue to the provider developers.\n\n"+ + "HTTP Error: "+err.Error(), + ) + + return + } + + // Treat HTTP 404 Not Found status as a signal to recreate resource + // and return early + if httpResp.StatusCode == http.StatusNotFound { + resp.State.RemoveResource(ctx) + + return + } + + // Update data from httpResp + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} +``` + ### Update -`Update` makes the necessary API calls to modify the existing resource to match the configuration and then to persist that resource's data into the Terraform state. This is usually accomplished by: +The [`resource.Resource` interface `Update` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#Resource.Update) makes the necessary calls to modify the existing resource to match the configuration and then persist the updated state. -1. [Reading the plan data](/plugin/framework/accessing-values) from the [`resource.UpdateRequest`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#UpdateRequest) -1. Using the configured API client injected into the resource by the resource - type's `NewResource` method -1. [Writing to the state](/plugin/framework/writing-state). +If the resource does not support modification and should always be recreated on configuration value updates, this method logic can be left empty and ensure all configurable schema attributes implement the [`resource.RequiresReplace` plan modifier](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#RequiresReplace). + +Implement the `Update` method by: + +1. [Accessing the data](/plugin/framework/accessing-values) from the [`resource.UpdateRequest` type](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#UpdateRequest). Most use cases should access the plan data in the [`resource.UpdateRequest.Plan` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#UpdateRequest.Plan). +1. Performing logic or external calls to modify the resource. +1. [Writing state data](/plugin/framework/writing-state) into the [`resource.UpdateResponse.State` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#UpdateResponse.State). It is very important that every known value in the plan ends up in state as a byte-for-byte match, or Terraform will throw errors. The plan is the provider's @@ -121,52 +260,108 @@ contract with Terraform: the provider can only change values that are very important that every unknown value in the plan gets a known, concrete value when it's set in the state; the state can never hold any unknown values. -### Delete +If the logic needs to return [warning or error diagnostics](/plugin/framework/diagnostics), they can added into the [`resource.UpdateResponse.Diagnostics` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#UpdateResponse.Diagnostics). Only successfully modified parts of the resource should be return updated data in the state response. -`Delete` makes the necessary API calls to destroy a resource and then to remove that resource from the Terraform state. This is usually accomplished by: - -1. [Reading the prior state data](/plugin/framework/accessing-values) from the - [`resource.DeleteRequest`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#DeleteRequest) -1. Using the configured API client injected into the resource by the resource - type's `NewResource` method +### Delete -Terraform 1.3 and later enables deletion planning, which resources can implement to return warning and error diagnostics. For additional information, refer to the [resource plan modification documentation](/plugin/framework/resources/plan-modification#resource-destroy-plan-diagnostics). +The [`resource.Resource` interface `Delete` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#Resource.Delete) makes the necessary API calls to destroy a resource and then to remove that resource from the Terraform state. -### ImportState +Implement the `Delete` method by: -`ImportState` is an optional method that implements resource [import](/cli/import). This functionality creates an initial Terraform state to bring the resource under management via the [`terraform import` command](/cli/commands/import). This method must provide enough state for the resource to be successfully refreshed via the `Read` method. This is usually accomplished by: +1. [Accessing prior state data](/plugin/framework/accessing-values) from the [`resource.DeleteRequest.State` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#DeleteRequest.State). +1. Performing logic or external calls to destroy the resource. -1. Using the import identifier from the [`resource.ImportStateRequest`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ImportStateRequest) to [set state data](/plugin/framework/writing-state) in the - [`resource.ImportStateResponse`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ImportStateResponse). +Terraform 1.3 and later enables deletion planning, which resources can implement to return warning and error diagnostics. For additional information, refer to the [resource plan modification documentation](/plugin/framework/resources/plan-modification#resource-destroy-plan-diagnostics). -The [`resource.ImportStatePassthroughID` function](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ImportStatePassthroughID) is available to simplify writing the import identifier to an attribute. +If the logic needs to return [warning or error diagnostics](/plugin/framework/diagnostics), they can added into the [`resource.DeleteResponse.Diagnostics` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#DeleteResponse.Diagnostics). Any errors will prevent the framework from automatically calling the [`RemoveResource` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/tfsdk#State.RemoveResource) on the [`resource.DeleteResponse.State` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#DeleteResponse.State). If the resource should still be removed from state, call the `RemoveResource` method manually. -Refer to [Resource Import](/plugin/framework/resources/import) for more details and code examples. +If the logic needs to skip a condition, such as an API error, where the resource no longer exists then the logic can return early. -### UpgradeState +In this example, the `Delete` function allows HTTP 200 OK and 404 Not Found statuses to complete successfully without raising any errors: -`UpgradeState` is an optional method that implements resource [state](/language/state) upgrades when there are breaking changes to the [schema](/plugin/framework/schemas). +```go +type ThingResource struct { + // client is configured via a Configure method, which is not shown in this + // example for brevity. Refer to the Configure Resources documentation for + // additional details for setting up resources with external clients. + client *http.Client +} -Refer to [State Upgrades](/plugin/framework/resources/state-upgrade) for more details and code examples. +func (r *ThingResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data ThingResourceModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + httpReq := http.NewRequestWithContext( + ctx, + http.MethodDelete, + fmt.Sprintf("http://example.com/thing/%s", data.ID), + nil, + ) + + httpResp, err := d.client.Do(httpReq) + defer httpResp.Body.Close() + + if err != nil { + resp.Diagnostics.AddError( + "Unable to Delete Resource", + "An unexpected error occurred while attempting to delete the resource. "+ + "Please retry the operation or report this issue to the provider developers.\n\n"+ + "HTTP Error: "+err.Error(), + ) + + return + } + + // Treat HTTP 404 Not Found status as a signal to return early + if httpResp.StatusCode != http.StatusNotFound && httpResp.StatusCode != http.StatusOK { + resp.Diagnostics.AddError( + "Unable to Delete Resource", + "An unexpected error occurred while attempting to delete the resource. "+ + "Please retry the operation or report this issue to the provider developers.\n\n"+ + "HTTP Status: "+httpResp.Status, + ) + + return + } + + // If the logic reaches here, it implicitly succeeded and will remove + // the resource from state if there are no other errors. +} +``` ## Add Resource to Provider -To make new resources available to practitioners, add them to the `GetResources` method on the [provider](/plugin/framework/providers). -The key must be the name of the resource, including the provider prefix, and -the value must be an instance of the resource type. +Resources become available to practitioners when they are included in the [provider](/plugin/framework/providers) implementation via the [`provider.ProviderWithResources` interface `Resources` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#ProviderWithResources.Resources). -**Example** +In this example, the `ThingResource` type, which implements the `resource.Resource` interface, is added to the provider implementation: ```go -func (p *provider) GetResources(_ context.Context) (map[string]provider.ResourceType, - diag.Diagnostics) { - return map[string]provider.ResourceType{ - "example_compute_instance": computeInstanceResourceType{}, - }, nil +// With the provider.Provider implementation +func (p *ExampleCloudProvider) Resources(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + func() resource.Resource { + return &ThingResource{}, + }, + } } ``` -## Further Resource Capabilities +To simplify provider implementations, a named function can be created with the resource implementation. -- [Plan modification](/plugin/framework/resources/plan-modification) helps practitioners understand expected behaviors for your resource during changes, such as default values for missing configurations or requiring replacement. -- [Validation](/plugin/framework/validation) helps practitioners understand the required syntax, types, and acceptable values for your resource. +In this example, the `ThingResource` code includes an additional `NewThingResource` function, which simplifies the provider implementation: + +```go +// With the provider.Provider implementation +func (p *ExampleCloudProvider) Resources(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + NewThingResource, + } +} + +// With the resource.Resource implementation +func NewThingResource() resource.Resource { + return &ThingResource{} +} +``` diff --git a/website/docs/plugin/framework/resources/state-upgrade.mdx b/website/docs/plugin/framework/resources/state-upgrade.mdx index 93266846d..01f3106d0 100644 --- a/website/docs/plugin/framework/resources/state-upgrade.mdx +++ b/website/docs/plugin/framework/resources/state-upgrade.mdx @@ -22,17 +22,18 @@ A resource schema captures the structure and types of the resource [state](/lang ## Implementing State Upgrade Support -Ensure the [`tfsdk.Schema` type `Version` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/tfsdk#Schema.Version) for the [`provider.ResourceType`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#ResourceType) is greater than `0`, then implement the [`resource.ResourceWithStateUpgrade` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ResourceWithStateUpgrade) for the [`resource.Resource`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#Resource). Conventionally the version is incremented by `1` for each state upgrade. +Ensure the [`tfsdk.Schema` type `Version` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/tfsdk#Schema.Version) for the [`resource.Resource`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#Resource) is greater than `0`, then implement the [`resource.ResourceWithStateUpgrade` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#ResourceWithStateUpgrade) for the [`resource.Resource`](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/resource#Resource). Conventionally the version is incremented by `1` for each state upgrade. -This example shows a `ResourceType` which incremented the `Schema` type `Version` field: +This example shows a `Resource` with the necessary `StateUpgrade` method to implement the `ResourceWithStateUpgrade` interface: ```go -// Other ResourceType methods are omitted in this example -var _ provider.ResourceType = exampleResourceType{} +// Other Resource methods are omitted in this example +var _ resource.Resource = &ThingResource{} +var _ resource.ResourceWithUpgradeState = &ThingResource{} -type exampleResourceType struct{/* ... */} +type ThingResource struct{/* ... */} -func (t exampleResourceType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { +func (r *ThingResource) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return tfsdk.Schema{ // ... other fields ... @@ -41,18 +42,8 @@ func (t exampleResourceType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Di Version: 2, } } -``` - -This example shows a `Resource` with the necessary `StateUpgrade` method to implement the `ResourceWithStateUpgrade` interface: - -```go -// Other Resource methods are omitted in this example -var _ resource.Resource = exampleResource{} -var _ resource.ResourceWithUpgradeState = exampleResource{} - -type exampleResource struct{/* ... */} -func (r exampleResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { +func (r *ThingResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { return map[int64]resource.StateUpgrader{ // State upgrade implementation from 0 (prior state version) to 2 (Schema.Version) 0: { @@ -81,28 +72,25 @@ Implement the [`StateUpgrader` type `PriorSchema` field](https://pkg.go.dev/gith This example shows a resource that changes the type for two attributes, using the `PriorSchema` approach: ```go -// Other ResourceType methods are omitted in this example -var _ provider.ResourceType = exampleResourceType{} // Other Resource methods are omitted in this example -var _ resource.Resource = exampleResource{} -var _ resource.ResourceWithUpgradeState = exampleResource{} +var _ resource.Resource = &ThingResource{} +var _ resource.ResourceWithUpgradeState = &ThingResource{} -type exampleResourceType struct{/* ... */} -type exampleResource struct{/* ... */} +type ThingResource struct{/* ... */} -type exampleResourceDataV0 struct { +type ThingResourceModelV0 struct { Id string `tfsdk:"id"` OptionalAttribute *bool `tfsdk:"optional_attribute"` RequiredAttribute bool `tfsdk:"required_attribute"` } -type exampleResourceDataV1 struct { +type ThingResourceModelV1 struct { Id string `tfsdk:"id"` OptionalAttribute *string `tfsdk:"optional_attribute"` RequiredAttribute string `tfsdk:"required_attribute"` } -func (t exampleResourceType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { +func (r *ThingResource) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return tfsdk.Schema{ Attributes: map[string]Attribute{ "id": { @@ -124,7 +112,7 @@ func (t exampleResourceType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Di } } -func (r exampleResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { +func (r *ThingResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { return map[int64]resource.StateUpgrader{ // State upgrade implementation from 0 (prior state version) to 1 (Schema.Version) 0: { @@ -145,7 +133,7 @@ func (r exampleResource) UpgradeState(ctx context.Context) map[int64]resource.St }, }, StateUpgrader: func(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { - var priorStateData exampleResourceDataV0 + var priorStateData ThingResourceModelV0 resp.Diagnostics.Append(req.State.Get(ctx, &priorStateData)...) @@ -153,7 +141,7 @@ func (r exampleResource) UpgradeState(ctx context.Context) map[int64]resource.St return } - upgradedStateData := exampleResourceDataV1{ + upgradedStateData := ThingResourceModelV1{ Id: priorStateData.Id, RequiredAttribute: fmt.Sprintf("%t", priorStateData.RequiredAttribute), } @@ -177,13 +165,11 @@ Read prior state data from the [`resource.UpgradeStateRequest` type `RawState` f This example shows a resource that changes the type for two attributes, using the `RawState` approach for the request and `DynamicValue` approach for the response: ```go -// Other ResourceType methods are omitted in this example -var _ provider.ResourceType = exampleResourceType{} // Other Resource methods are omitted in this example -var _ resource.Resource = exampleResource{} -var _ resource.ResourceWithUpgradeState = exampleResource{} +var _ resource.Resource = &ThingResource{} +var _ resource.ResourceWithUpgradeState = &ThingResource{} -var exampleResourceTftypesDataV0 = tftypes.Object{ +var ThingResourceTftypesDataV0 = tftypes.Object{ AttributeTypes: map[string]tftypes.Type{ "id": tftypes.String, "optional_attribute": tftypes.Bool, @@ -191,7 +177,7 @@ var exampleResourceTftypesDataV0 = tftypes.Object{ }, } -var exampleResourceTftypesDataV1 = tftypes.Object{ +var ThingResourceTftypesDataV1 = tftypes.Object{ AttributeTypes: map[string]tftypes.Type{ "id": tftypes.String, "optional_attribute": tftypes.String, @@ -199,10 +185,9 @@ var exampleResourceTftypesDataV1 = tftypes.Object{ }, } -type exampleResourceType struct{/* ... */} -type exampleResource struct{/* ... */} +type ThingResource struct{/* ... */} -func (t exampleResourceType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { +func (r *ThingResource) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return tfsdk.Schema{ Attributes: map[string]Attribute{ "id": { @@ -224,14 +209,14 @@ func (t exampleResourceType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Di } } -func (r exampleResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { +func (r *ThingResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { return map[int64]resource.StateUpgrader{ // State upgrade implementation from 0 (prior state version) to 1 (Schema.Version) 0: { StateUpgrader: func(ctx context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) { // Refer also to the RawState type JSON field which can be used // with json.Unmarshal() - rawStateValue, err := req.RawState.Unmarshal(exampleResourceTftypesDataV0) + rawStateValue, err := req.RawState.Unmarshal(ThingResourceTftypesDataV0) if err != nil { resp.Diagnostics.AddError( @@ -281,8 +266,8 @@ func (r exampleResource) UpgradeState(ctx context.Context) map[int64]resource.St } dynamicValue, err := tfprotov6.NewDynamicValue( - exampleResourceTftypesDataV1, - tftypes.NewValue(exampleResourceTftypesDataV1, map[string]tftypes.Value{ + ThingResourceTftypesDataV1, + tftypes.NewValue(ThingResourceTftypesDataV1, map[string]tftypes.Value{ "id": rawState["id"], "optional_attribute": tftypes.NewValue(tftypes.String, optionalAttributeString), "required_attribute": tftypes.NewValue(tftypes.String, fmt.Sprintf("%t", requiredAttribute)),