diff --git a/.changelog/438.txt b/.changelog/438.txt new file mode 100644 index 000000000..59b3461d3 --- /dev/null +++ b/.changelog/438.txt @@ -0,0 +1,3 @@ +```release-note:breaking-change +tfsdk: The `Schema` type `AttributeAtPath` method now returns a `fwschema.Attribute` interface instead of a `tfsdk.Attribute` type. Consumers will need to update from direct field usage to similarly named interface method calls. +``` diff --git a/internal/fromproto5/applyresourcechange.go b/internal/fromproto5/applyresourcechange.go index cdbc7f82a..f0392aa05 100644 --- a/internal/fromproto5/applyresourcechange.go +++ b/internal/fromproto5/applyresourcechange.go @@ -4,15 +4,15 @@ import ( "context" "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/tfsdk" "github.com/hashicorp/terraform-plugin-go/tfprotov5" ) // ApplyResourceChangeRequest returns the *fwserver.ApplyResourceChangeRequest // equivalent of a *tfprotov5.ApplyResourceChangeRequest. -func ApplyResourceChangeRequest(ctx context.Context, proto5 *tfprotov5.ApplyResourceChangeRequest, resourceType provider.ResourceType, resourceSchema *tfsdk.Schema, providerMetaSchema *tfsdk.Schema) (*fwserver.ApplyResourceChangeRequest, diag.Diagnostics) { +func ApplyResourceChangeRequest(ctx context.Context, proto5 *tfprotov5.ApplyResourceChangeRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.ApplyResourceChangeRequest, diag.Diagnostics) { if proto5 == nil { return nil, nil } @@ -35,7 +35,7 @@ func ApplyResourceChangeRequest(ctx context.Context, proto5 *tfprotov5.ApplyReso fw := &fwserver.ApplyResourceChangeRequest{ PlannedPrivate: proto5.PlannedPrivate, - ResourceSchema: *resourceSchema, + ResourceSchema: resourceSchema, ResourceType: resourceType, } diff --git a/internal/fromproto5/applyresourcechange_test.go b/internal/fromproto5/applyresourcechange_test.go index 1bf7e4aa2..947c963ab 100644 --- a/internal/fromproto5/applyresourcechange_test.go +++ b/internal/fromproto5/applyresourcechange_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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" @@ -45,9 +46,9 @@ func TestApplyResourceChangeRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov5.ApplyResourceChangeRequest - resourceSchema *tfsdk.Schema + resourceSchema fwschema.Schema resourceType provider.ResourceType - providerMetaSchema *tfsdk.Schema + providerMetaSchema fwschema.Schema expected *fwserver.ApplyResourceChangeRequest expectedDiagnostics diag.Diagnostics }{ @@ -93,7 +94,7 @@ func TestApplyResourceChangeRequest(t *testing.T) { Raw: testProto5Value, Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "plannedstate-missing-schema": { @@ -121,7 +122,7 @@ func TestApplyResourceChangeRequest(t *testing.T) { Raw: testProto5Value, Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "plannedprivate": { @@ -131,7 +132,7 @@ func TestApplyResourceChangeRequest(t *testing.T) { resourceSchema: testFwSchema, expected: &fwserver.ApplyResourceChangeRequest{ PlannedPrivate: []byte("{}"), - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "priorstate-missing-schema": { @@ -159,7 +160,7 @@ func TestApplyResourceChangeRequest(t *testing.T) { Raw: testProto5Value, Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "providermeta-missing-data": { @@ -171,7 +172,7 @@ func TestApplyResourceChangeRequest(t *testing.T) { Raw: tftypes.NewValue(testProto5Type, nil), Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "providermeta-missing-schema": { @@ -181,7 +182,7 @@ func TestApplyResourceChangeRequest(t *testing.T) { resourceSchema: testFwSchema, expected: &fwserver.ApplyResourceChangeRequest{ // This intentionally should not include ProviderMeta - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "providermeta": { @@ -195,7 +196,7 @@ func TestApplyResourceChangeRequest(t *testing.T) { Raw: testProto5Value, Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, } diff --git a/internal/fromproto5/config.go b/internal/fromproto5/config.go index fd39d7539..3702ade6a 100644 --- a/internal/fromproto5/config.go +++ b/internal/fromproto5/config.go @@ -4,13 +4,14 @@ import ( "context" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-go/tfprotov5" ) // Config returns the *tfsdk.Config for a *tfprotov5.DynamicValue and -// *tfsdk.Schema. -func Config(ctx context.Context, proto5DynamicValue *tfprotov5.DynamicValue, schema *tfsdk.Schema) (*tfsdk.Config, diag.Diagnostics) { +// fwschema.Schema. +func Config(ctx context.Context, proto5DynamicValue *tfprotov5.DynamicValue, schema fwschema.Schema) (*tfsdk.Config, diag.Diagnostics) { if proto5DynamicValue == nil { return nil, nil } @@ -46,7 +47,7 @@ func Config(ctx context.Context, proto5DynamicValue *tfprotov5.DynamicValue, sch fw := &tfsdk.Config{ Raw: proto5Value, - Schema: *schema, + Schema: tfsdkSchema(schema), } return fw, nil diff --git a/internal/fromproto5/config_test.go b/internal/fromproto5/config_test.go index 0f9ce0a1c..58526d417 100644 --- a/internal/fromproto5/config_test.go +++ b/internal/fromproto5/config_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-go/tfprotov5" @@ -52,7 +53,7 @@ func TestConfig(t *testing.T) { testCases := map[string]struct { input *tfprotov5.DynamicValue - schema *tfsdk.Schema + schema fwschema.Schema expected *tfsdk.Config expectedDiagnostics diag.Diagnostics }{ diff --git a/internal/fromproto5/configureprovider.go b/internal/fromproto5/configureprovider.go index 5e4f021a4..9ce200f3a 100644 --- a/internal/fromproto5/configureprovider.go +++ b/internal/fromproto5/configureprovider.go @@ -4,14 +4,14 @@ import ( "context" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/provider" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-go/tfprotov5" ) // ConfigureProviderRequest returns the *fwserver.ConfigureProviderRequest // equivalent of a *tfprotov5.ConfigureProviderRequest. -func ConfigureProviderRequest(ctx context.Context, proto5 *tfprotov5.ConfigureProviderRequest, providerSchema *tfsdk.Schema) (*provider.ConfigureRequest, diag.Diagnostics) { +func ConfigureProviderRequest(ctx context.Context, proto5 *tfprotov5.ConfigureProviderRequest, providerSchema fwschema.Schema) (*provider.ConfigureRequest, diag.Diagnostics) { if proto5 == nil { return nil, nil } diff --git a/internal/fromproto5/configureprovider_test.go b/internal/fromproto5/configureprovider_test.go index a7d640cc5..3401eacb2 100644 --- a/internal/fromproto5/configureprovider_test.go +++ b/internal/fromproto5/configureprovider_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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/provider" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -44,7 +45,7 @@ func TestConfigureProviderRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov5.ConfigureProviderRequest - providerSchema *tfsdk.Schema + providerSchema fwschema.Schema expected *provider.ConfigureRequest expectedDiagnostics diag.Diagnostics }{ diff --git a/internal/fromproto5/importresourcestate.go b/internal/fromproto5/importresourcestate.go index 6ce49a7bc..e1b061bef 100644 --- a/internal/fromproto5/importresourcestate.go +++ b/internal/fromproto5/importresourcestate.go @@ -4,6 +4,7 @@ import ( "context" "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/tfsdk" @@ -13,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 *tfsdk.Schema) (*fwserver.ImportResourceStateRequest, diag.Diagnostics) { +func ImportResourceStateRequest(ctx context.Context, proto5 *tfprotov5.ImportResourceStateRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema) (*fwserver.ImportResourceStateRequest, diag.Diagnostics) { if proto5 == nil { return nil, nil } @@ -37,7 +38,7 @@ func ImportResourceStateRequest(ctx context.Context, proto5 *tfprotov5.ImportRes fw := &fwserver.ImportResourceStateRequest{ EmptyState: tfsdk.State{ Raw: tftypes.NewValue(resourceSchema.TerraformType(ctx), nil), - Schema: *resourceSchema, + Schema: tfsdkSchema(resourceSchema), }, ID: proto5.ID, ResourceType: resourceType, diff --git a/internal/fromproto5/importresourcestate_test.go b/internal/fromproto5/importresourcestate_test.go index 588fc1a7a..ca3ee865b 100644 --- a/internal/fromproto5/importresourcestate_test.go +++ b/internal/fromproto5/importresourcestate_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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" @@ -34,7 +35,7 @@ func TestImportResourceStateRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov5.ImportResourceStateRequest - resourceSchema *tfsdk.Schema + resourceSchema fwschema.Schema resourceType provider.ResourceType expected *fwserver.ImportResourceStateRequest expectedDiagnostics diag.Diagnostics diff --git a/internal/fromproto5/plan.go b/internal/fromproto5/plan.go index 670fa6ea4..9237a5c14 100644 --- a/internal/fromproto5/plan.go +++ b/internal/fromproto5/plan.go @@ -4,13 +4,14 @@ import ( "context" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-go/tfprotov5" ) // Plan returns the *tfsdk.Plan for a *tfprotov5.DynamicValue and -// *tfsdk.Schema. -func Plan(ctx context.Context, proto5DynamicValue *tfprotov5.DynamicValue, schema *tfsdk.Schema) (*tfsdk.Plan, diag.Diagnostics) { +// fwschema.Schema. +func Plan(ctx context.Context, proto5DynamicValue *tfprotov5.DynamicValue, schema fwschema.Schema) (*tfsdk.Plan, diag.Diagnostics) { if proto5DynamicValue == nil { return nil, nil } @@ -46,7 +47,7 @@ func Plan(ctx context.Context, proto5DynamicValue *tfprotov5.DynamicValue, schem fw := &tfsdk.Plan{ Raw: proto5Value, - Schema: *schema, + Schema: tfsdkSchema(schema), } return fw, nil diff --git a/internal/fromproto5/plan_test.go b/internal/fromproto5/plan_test.go index fa7e2832a..5f76573b3 100644 --- a/internal/fromproto5/plan_test.go +++ b/internal/fromproto5/plan_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-go/tfprotov5" @@ -52,7 +53,7 @@ func TestPlan(t *testing.T) { testCases := map[string]struct { input *tfprotov5.DynamicValue - schema *tfsdk.Schema + schema fwschema.Schema expected *tfsdk.Plan expectedDiagnostics diag.Diagnostics }{ diff --git a/internal/fromproto5/planresourcechange.go b/internal/fromproto5/planresourcechange.go index 430f73b56..1745a129a 100644 --- a/internal/fromproto5/planresourcechange.go +++ b/internal/fromproto5/planresourcechange.go @@ -4,15 +4,15 @@ import ( "context" "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/tfsdk" "github.com/hashicorp/terraform-plugin-go/tfprotov5" ) // PlanResourceChangeRequest returns the *fwserver.PlanResourceChangeRequest // equivalent of a *tfprotov5.PlanResourceChangeRequest. -func PlanResourceChangeRequest(ctx context.Context, proto5 *tfprotov5.PlanResourceChangeRequest, resourceType provider.ResourceType, resourceSchema *tfsdk.Schema, providerMetaSchema *tfsdk.Schema) (*fwserver.PlanResourceChangeRequest, diag.Diagnostics) { +func PlanResourceChangeRequest(ctx context.Context, proto5 *tfprotov5.PlanResourceChangeRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.PlanResourceChangeRequest, diag.Diagnostics) { if proto5 == nil { return nil, nil } @@ -35,7 +35,7 @@ func PlanResourceChangeRequest(ctx context.Context, proto5 *tfprotov5.PlanResour fw := &fwserver.PlanResourceChangeRequest{ PriorPrivate: proto5.PriorPrivate, - ResourceSchema: *resourceSchema, + ResourceSchema: resourceSchema, ResourceType: resourceType, } diff --git a/internal/fromproto5/planresourcechange_test.go b/internal/fromproto5/planresourcechange_test.go index fcc4878f5..a34d9f9af 100644 --- a/internal/fromproto5/planresourcechange_test.go +++ b/internal/fromproto5/planresourcechange_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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" @@ -45,9 +46,9 @@ func TestPlanResourceChangeRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov5.PlanResourceChangeRequest - resourceSchema *tfsdk.Schema + resourceSchema fwschema.Schema resourceType provider.ResourceType - providerMetaSchema *tfsdk.Schema + providerMetaSchema fwschema.Schema expected *fwserver.PlanResourceChangeRequest expectedDiagnostics diag.Diagnostics }{ @@ -93,7 +94,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { Raw: testProto5Value, Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "priorprivate": { @@ -103,7 +104,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { resourceSchema: testFwSchema, expected: &fwserver.PlanResourceChangeRequest{ PriorPrivate: []byte("{}"), - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "priorstate-missing-schema": { @@ -131,7 +132,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { Raw: testProto5Value, Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "proposednewstate-missing-schema": { @@ -159,7 +160,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { Raw: testProto5Value, Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "providermeta-missing-data": { @@ -171,7 +172,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { Raw: tftypes.NewValue(testProto5Type, nil), Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "providermeta-missing-schema": { @@ -181,7 +182,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { resourceSchema: testFwSchema, expected: &fwserver.PlanResourceChangeRequest{ // This intentionally should not include ProviderMeta - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "providermeta": { @@ -195,7 +196,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { Raw: testProto5Value, Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, } diff --git a/internal/fromproto5/prepareproviderconfig.go b/internal/fromproto5/prepareproviderconfig.go index 5b0bfe8f4..f85b9352b 100644 --- a/internal/fromproto5/prepareproviderconfig.go +++ b/internal/fromproto5/prepareproviderconfig.go @@ -4,14 +4,14 @@ import ( "context" "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/tfsdk" "github.com/hashicorp/terraform-plugin-go/tfprotov5" ) // PrepareProviderConfigRequest returns the *fwserver.ValidateProviderConfigRequest // equivalent of a *tfprotov5.PrepareProviderConfigRequest. -func PrepareProviderConfigRequest(ctx context.Context, proto5 *tfprotov5.PrepareProviderConfigRequest, providerSchema *tfsdk.Schema) (*fwserver.ValidateProviderConfigRequest, diag.Diagnostics) { +func PrepareProviderConfigRequest(ctx context.Context, proto5 *tfprotov5.PrepareProviderConfigRequest, providerSchema fwschema.Schema) (*fwserver.ValidateProviderConfigRequest, diag.Diagnostics) { if proto5 == nil { return nil, nil } diff --git a/internal/fromproto5/prepareproviderconfig_test.go b/internal/fromproto5/prepareproviderconfig_test.go index 3d260c40d..4fc561a0f 100644 --- a/internal/fromproto5/prepareproviderconfig_test.go +++ b/internal/fromproto5/prepareproviderconfig_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -44,7 +45,7 @@ func TestValidateProviderConfigRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov5.PrepareProviderConfigRequest - providerSchema *tfsdk.Schema + providerSchema fwschema.Schema expected *fwserver.ValidateProviderConfigRequest expectedDiagnostics diag.Diagnostics }{ diff --git a/internal/fromproto5/providermeta.go b/internal/fromproto5/providermeta.go index 9945fc18d..23832ea60 100644 --- a/internal/fromproto5/providermeta.go +++ b/internal/fromproto5/providermeta.go @@ -4,18 +4,19 @@ import ( "context" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-go/tfprotov5" "github.com/hashicorp/terraform-plugin-go/tftypes" ) // ProviderMeta returns the *tfsdk.Config for a *tfprotov5.DynamicValue and -// *tfsdk.Schema. This data handling is different than Config to simplify +// fwschema.Schema. This data handling is different than Config to simplify // implementors, in that: // // - Missing Schema will return nil, rather than an error // - Missing DynamicValue will return nil typed Value, rather than an error -func ProviderMeta(ctx context.Context, proto5DynamicValue *tfprotov5.DynamicValue, schema *tfsdk.Schema) (*tfsdk.Config, diag.Diagnostics) { +func ProviderMeta(ctx context.Context, proto5DynamicValue *tfprotov5.DynamicValue, schema fwschema.Schema) (*tfsdk.Config, diag.Diagnostics) { if schema == nil { return nil, nil } @@ -24,7 +25,7 @@ func ProviderMeta(ctx context.Context, proto5DynamicValue *tfprotov5.DynamicValu fw := &tfsdk.Config{ Raw: tftypes.NewValue(schema.TerraformType(ctx), nil), - Schema: *schema, + Schema: tfsdkSchema(schema), } if proto5DynamicValue == nil { diff --git a/internal/fromproto5/providermeta_test.go b/internal/fromproto5/providermeta_test.go index 3c319188b..43f664bf0 100644 --- a/internal/fromproto5/providermeta_test.go +++ b/internal/fromproto5/providermeta_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-go/tfprotov5" @@ -52,7 +53,7 @@ func TestProviderMeta(t *testing.T) { testCases := map[string]struct { input *tfprotov5.DynamicValue - schema *tfsdk.Schema + schema fwschema.Schema expected *tfsdk.Config expectedDiagnostics diag.Diagnostics }{ diff --git a/internal/fromproto5/readdatasource.go b/internal/fromproto5/readdatasource.go index 6ce9df076..b390f4233 100644 --- a/internal/fromproto5/readdatasource.go +++ b/internal/fromproto5/readdatasource.go @@ -4,15 +4,15 @@ import ( "context" "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/tfsdk" "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 *tfsdk.Schema, providerMetaSchema *tfsdk.Schema) (*fwserver.ReadDataSourceRequest, diag.Diagnostics) { +func ReadDataSourceRequest(ctx context.Context, proto5 *tfprotov5.ReadDataSourceRequest, dataSourceType provider.DataSourceType, dataSourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.ReadDataSourceRequest, diag.Diagnostics) { if proto5 == nil { return nil, nil } @@ -34,7 +34,7 @@ func ReadDataSourceRequest(ctx context.Context, proto5 *tfprotov5.ReadDataSource } fw := &fwserver.ReadDataSourceRequest{ - DataSourceSchema: *dataSourceSchema, + DataSourceSchema: dataSourceSchema, DataSourceType: dataSourceType, } diff --git a/internal/fromproto5/readdatasource_test.go b/internal/fromproto5/readdatasource_test.go index 9fbd51571..949442790 100644 --- a/internal/fromproto5/readdatasource_test.go +++ b/internal/fromproto5/readdatasource_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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" @@ -45,9 +46,9 @@ func TestReadDataSourceRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov5.ReadDataSourceRequest - dataSourceSchema *tfsdk.Schema + dataSourceSchema fwschema.Schema dataSourceType provider.DataSourceType - providerMetaSchema *tfsdk.Schema + providerMetaSchema fwschema.Schema expected *fwserver.ReadDataSourceRequest expectedDiagnostics diag.Diagnostics }{ @@ -93,7 +94,7 @@ func TestReadDataSourceRequest(t *testing.T) { Raw: testProto5Value, Schema: *testFwSchema, }, - DataSourceSchema: *testFwSchema, + DataSourceSchema: testFwSchema, }, }, "providermeta-missing-data": { @@ -101,7 +102,7 @@ func TestReadDataSourceRequest(t *testing.T) { dataSourceSchema: testFwSchema, providerMetaSchema: testFwSchema, expected: &fwserver.ReadDataSourceRequest{ - DataSourceSchema: *testFwSchema, + DataSourceSchema: testFwSchema, ProviderMeta: &tfsdk.Config{ Raw: tftypes.NewValue(testProto5Type, nil), Schema: *testFwSchema, @@ -114,7 +115,7 @@ func TestReadDataSourceRequest(t *testing.T) { }, dataSourceSchema: testFwSchema, expected: &fwserver.ReadDataSourceRequest{ - DataSourceSchema: *testFwSchema, + DataSourceSchema: testFwSchema, // This intentionally should not include ProviderMeta }, }, @@ -125,7 +126,7 @@ func TestReadDataSourceRequest(t *testing.T) { dataSourceSchema: testFwSchema, providerMetaSchema: testFwSchema, expected: &fwserver.ReadDataSourceRequest{ - DataSourceSchema: *testFwSchema, + DataSourceSchema: testFwSchema, ProviderMeta: &tfsdk.Config{ Raw: testProto5Value, Schema: *testFwSchema, diff --git a/internal/fromproto5/readresource.go b/internal/fromproto5/readresource.go index 44740871b..1c3f99bf2 100644 --- a/internal/fromproto5/readresource.go +++ b/internal/fromproto5/readresource.go @@ -4,15 +4,15 @@ import ( "context" "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/tfsdk" "github.com/hashicorp/terraform-plugin-go/tfprotov5" ) // ReadResourceRequest returns the *fwserver.ReadResourceRequest // equivalent of a *tfprotov5.ReadResourceRequest. -func ReadResourceRequest(ctx context.Context, proto5 *tfprotov5.ReadResourceRequest, resourceType provider.ResourceType, resourceSchema *tfsdk.Schema, providerMetaSchema *tfsdk.Schema) (*fwserver.ReadResourceRequest, diag.Diagnostics) { +func ReadResourceRequest(ctx context.Context, proto5 *tfprotov5.ReadResourceRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.ReadResourceRequest, diag.Diagnostics) { if proto5 == nil { return nil, nil } diff --git a/internal/fromproto5/readresource_test.go b/internal/fromproto5/readresource_test.go index 623795493..302421f67 100644 --- a/internal/fromproto5/readresource_test.go +++ b/internal/fromproto5/readresource_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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" @@ -45,9 +46,9 @@ func TestReadResourceRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov5.ReadResourceRequest - resourceSchema *tfsdk.Schema + resourceSchema fwschema.Schema resourceType provider.ResourceType - providerMetaSchema *tfsdk.Schema + providerMetaSchema fwschema.Schema expected *fwserver.ReadResourceRequest expectedDiagnostics diag.Diagnostics }{ diff --git a/internal/fromproto5/schema.go b/internal/fromproto5/schema.go new file mode 100644 index 000000000..267663916 --- /dev/null +++ b/internal/fromproto5/schema.go @@ -0,0 +1,22 @@ +package fromproto5 + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" +) + +// tfsdkSchema is a temporary function that will return a given fwschema.Schema +// as tfsdk.Schema or panic. This will be removed once tfsdk.Config, +// tfsdk.Plan, and tfsdk.State no longer use tfsdk.Schema directly or are +// replaced. +// 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 + default: + panic(fmt.Sprintf("unknown fromproto5 fwschema.Schema type: %T", s)) + } +} diff --git a/internal/fromproto5/state.go b/internal/fromproto5/state.go index c92db4a47..0253b9f24 100644 --- a/internal/fromproto5/state.go +++ b/internal/fromproto5/state.go @@ -4,13 +4,14 @@ import ( "context" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-go/tfprotov5" ) // State returns the *tfsdk.State for a *tfprotov5.DynamicValue and -// *tfsdk.Schema. -func State(ctx context.Context, proto5DynamicValue *tfprotov5.DynamicValue, schema *tfsdk.Schema) (*tfsdk.State, diag.Diagnostics) { +// fwschema.Schema. +func State(ctx context.Context, proto5DynamicValue *tfprotov5.DynamicValue, schema fwschema.Schema) (*tfsdk.State, diag.Diagnostics) { if proto5DynamicValue == nil { return nil, nil } @@ -46,7 +47,7 @@ func State(ctx context.Context, proto5DynamicValue *tfprotov5.DynamicValue, sche fw := &tfsdk.State{ Raw: proto5Value, - Schema: *schema, + Schema: tfsdkSchema(schema), } return fw, nil diff --git a/internal/fromproto5/state_test.go b/internal/fromproto5/state_test.go index 0ae31bbf9..a3754c2d3 100644 --- a/internal/fromproto5/state_test.go +++ b/internal/fromproto5/state_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-go/tfprotov5" @@ -52,7 +53,7 @@ func TestState(t *testing.T) { testCases := map[string]struct { input *tfprotov5.DynamicValue - schema *tfsdk.Schema + schema fwschema.Schema expected *tfsdk.State expectedDiagnostics diag.Diagnostics }{ diff --git a/internal/fromproto5/upgraderesourcestate.go b/internal/fromproto5/upgraderesourcestate.go index 36283c876..c8707134f 100644 --- a/internal/fromproto5/upgraderesourcestate.go +++ b/internal/fromproto5/upgraderesourcestate.go @@ -4,16 +4,16 @@ import ( "context" "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/tfsdk" "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 *tfsdk.Schema) (*fwserver.UpgradeResourceStateRequest, diag.Diagnostics) { +func UpgradeResourceStateRequest(ctx context.Context, proto5 *tfprotov5.UpgradeResourceStateRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema) (*fwserver.UpgradeResourceStateRequest, diag.Diagnostics) { if proto5 == nil { return nil, nil } @@ -36,7 +36,7 @@ func UpgradeResourceStateRequest(ctx context.Context, proto5 *tfprotov5.UpgradeR fw := &fwserver.UpgradeResourceStateRequest{ RawState: (*tfprotov6.RawState)(proto5.RawState), - ResourceSchema: *resourceSchema, + ResourceSchema: resourceSchema, ResourceType: resourceType, Version: proto5.Version, } diff --git a/internal/fromproto5/upgraderesourcestate_test.go b/internal/fromproto5/upgraderesourcestate_test.go index ccc4d8b26..c368c9fc3 100644 --- a/internal/fromproto5/upgraderesourcestate_test.go +++ b/internal/fromproto5/upgraderesourcestate_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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" @@ -28,7 +29,7 @@ func TestUpgradeResourceStateRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov5.UpgradeResourceStateRequest - resourceSchema *tfsdk.Schema + resourceSchema fwschema.Schema resourceType provider.ResourceType expected *fwserver.UpgradeResourceStateRequest expectedDiagnostics diag.Diagnostics @@ -48,14 +49,14 @@ func TestUpgradeResourceStateRequest(t *testing.T) { RawState: testNewTfprotov6RawState(t, map[string]interface{}{ "test_attribute": "test-value", }), - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "resourceschema": { input: &tfprotov5.UpgradeResourceStateRequest{}, resourceSchema: testFwSchema, expected: &fwserver.UpgradeResourceStateRequest{ - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "resourceschema-missing": { @@ -77,7 +78,7 @@ func TestUpgradeResourceStateRequest(t *testing.T) { }, resourceSchema: testFwSchema, expected: &fwserver.UpgradeResourceStateRequest{ - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, Version: 123, }, }, diff --git a/internal/fromproto5/validatedatasourceconfig.go b/internal/fromproto5/validatedatasourceconfig.go index 746b84b31..5dc05f5d1 100644 --- a/internal/fromproto5/validatedatasourceconfig.go +++ b/internal/fromproto5/validatedatasourceconfig.go @@ -4,15 +4,15 @@ import ( "context" "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/tfsdk" "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 *tfsdk.Schema) (*fwserver.ValidateDataSourceConfigRequest, diag.Diagnostics) { +func ValidateDataSourceConfigRequest(ctx context.Context, proto5 *tfprotov5.ValidateDataSourceConfigRequest, dataSourceType provider.DataSourceType, dataSourceSchema fwschema.Schema) (*fwserver.ValidateDataSourceConfigRequest, diag.Diagnostics) { if proto5 == nil { return nil, nil } diff --git a/internal/fromproto5/validatedatasourceconfig_test.go b/internal/fromproto5/validatedatasourceconfig_test.go index 72b3e29a5..4fde3951e 100644 --- a/internal/fromproto5/validatedatasourceconfig_test.go +++ b/internal/fromproto5/validatedatasourceconfig_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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" @@ -45,7 +46,7 @@ func TestValidateDataSourceConfigRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov5.ValidateDataSourceConfigRequest - dataSourceSchema *tfsdk.Schema + dataSourceSchema fwschema.Schema dataSourceType provider.DataSourceType expected *fwserver.ValidateDataSourceConfigRequest expectedDiagnostics diag.Diagnostics diff --git a/internal/fromproto5/validateresourcetypeconfig.go b/internal/fromproto5/validateresourcetypeconfig.go index 0d0a276f9..c36e4c6a9 100644 --- a/internal/fromproto5/validateresourcetypeconfig.go +++ b/internal/fromproto5/validateresourcetypeconfig.go @@ -4,15 +4,15 @@ import ( "context" "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/tfsdk" "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 *tfsdk.Schema) (*fwserver.ValidateResourceConfigRequest, diag.Diagnostics) { +func ValidateResourceTypeConfigRequest(ctx context.Context, proto5 *tfprotov5.ValidateResourceTypeConfigRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema) (*fwserver.ValidateResourceConfigRequest, diag.Diagnostics) { if proto5 == nil { return nil, nil } diff --git a/internal/fromproto5/validateresourcetypeconfig_test.go b/internal/fromproto5/validateresourcetypeconfig_test.go index 8ff9c134f..3683d1373 100644 --- a/internal/fromproto5/validateresourcetypeconfig_test.go +++ b/internal/fromproto5/validateresourcetypeconfig_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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" @@ -45,7 +46,7 @@ func TestValidateResourceTypeConfigRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov5.ValidateResourceTypeConfigRequest - resourceSchema *tfsdk.Schema + resourceSchema fwschema.Schema resourceType provider.ResourceType expected *fwserver.ValidateResourceConfigRequest expectedDiagnostics diag.Diagnostics diff --git a/internal/fromproto6/applyresourcechange.go b/internal/fromproto6/applyresourcechange.go index 678ce7bcf..22214253a 100644 --- a/internal/fromproto6/applyresourcechange.go +++ b/internal/fromproto6/applyresourcechange.go @@ -4,15 +4,15 @@ import ( "context" "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/tfsdk" "github.com/hashicorp/terraform-plugin-go/tfprotov6" ) // ApplyResourceChangeRequest returns the *fwserver.ApplyResourceChangeRequest // equivalent of a *tfprotov6.ApplyResourceChangeRequest. -func ApplyResourceChangeRequest(ctx context.Context, proto6 *tfprotov6.ApplyResourceChangeRequest, resourceType provider.ResourceType, resourceSchema *tfsdk.Schema, providerMetaSchema *tfsdk.Schema) (*fwserver.ApplyResourceChangeRequest, diag.Diagnostics) { +func ApplyResourceChangeRequest(ctx context.Context, proto6 *tfprotov6.ApplyResourceChangeRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.ApplyResourceChangeRequest, diag.Diagnostics) { if proto6 == nil { return nil, nil } @@ -35,7 +35,7 @@ func ApplyResourceChangeRequest(ctx context.Context, proto6 *tfprotov6.ApplyReso fw := &fwserver.ApplyResourceChangeRequest{ PlannedPrivate: proto6.PlannedPrivate, - ResourceSchema: *resourceSchema, + ResourceSchema: resourceSchema, ResourceType: resourceType, } diff --git a/internal/fromproto6/applyresourcechange_test.go b/internal/fromproto6/applyresourcechange_test.go index fd65f10f5..76a930cf1 100644 --- a/internal/fromproto6/applyresourcechange_test.go +++ b/internal/fromproto6/applyresourcechange_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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" @@ -45,9 +46,9 @@ func TestApplyResourceChangeRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov6.ApplyResourceChangeRequest - resourceSchema *tfsdk.Schema + resourceSchema fwschema.Schema resourceType provider.ResourceType - providerMetaSchema *tfsdk.Schema + providerMetaSchema fwschema.Schema expected *fwserver.ApplyResourceChangeRequest expectedDiagnostics diag.Diagnostics }{ @@ -93,7 +94,7 @@ func TestApplyResourceChangeRequest(t *testing.T) { Raw: testProto6Value, Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "plannedstate-missing-schema": { @@ -121,7 +122,7 @@ func TestApplyResourceChangeRequest(t *testing.T) { Raw: testProto6Value, Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "plannedprivate": { @@ -131,7 +132,7 @@ func TestApplyResourceChangeRequest(t *testing.T) { resourceSchema: testFwSchema, expected: &fwserver.ApplyResourceChangeRequest{ PlannedPrivate: []byte("{}"), - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "priorstate-missing-schema": { @@ -159,7 +160,7 @@ func TestApplyResourceChangeRequest(t *testing.T) { Raw: testProto6Value, Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "providermeta-missing-data": { @@ -171,7 +172,7 @@ func TestApplyResourceChangeRequest(t *testing.T) { Raw: tftypes.NewValue(testProto6Type, nil), Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "providermeta-missing-schema": { @@ -181,7 +182,7 @@ func TestApplyResourceChangeRequest(t *testing.T) { resourceSchema: testFwSchema, expected: &fwserver.ApplyResourceChangeRequest{ // This intentionally should not include ProviderMeta - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "providermeta": { @@ -195,7 +196,7 @@ func TestApplyResourceChangeRequest(t *testing.T) { Raw: testProto6Value, Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, } diff --git a/internal/fromproto6/config.go b/internal/fromproto6/config.go index 7b01aaff9..99be4283c 100644 --- a/internal/fromproto6/config.go +++ b/internal/fromproto6/config.go @@ -4,13 +4,14 @@ import ( "context" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-go/tfprotov6" ) // Config returns the *tfsdk.Config for a *tfprotov6.DynamicValue and -// *tfsdk.Schema. -func Config(ctx context.Context, proto6DynamicValue *tfprotov6.DynamicValue, schema *tfsdk.Schema) (*tfsdk.Config, diag.Diagnostics) { +// fwschema.Schema. +func Config(ctx context.Context, proto6DynamicValue *tfprotov6.DynamicValue, schema fwschema.Schema) (*tfsdk.Config, diag.Diagnostics) { if proto6DynamicValue == nil { return nil, nil } @@ -46,7 +47,7 @@ func Config(ctx context.Context, proto6DynamicValue *tfprotov6.DynamicValue, sch fw := &tfsdk.Config{ Raw: proto6Value, - Schema: *schema, + Schema: tfsdkSchema(schema), } return fw, nil diff --git a/internal/fromproto6/config_test.go b/internal/fromproto6/config_test.go index c5e394c4c..7e9edda06 100644 --- a/internal/fromproto6/config_test.go +++ b/internal/fromproto6/config_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-go/tfprotov6" @@ -52,7 +53,7 @@ func TestConfig(t *testing.T) { testCases := map[string]struct { input *tfprotov6.DynamicValue - schema *tfsdk.Schema + schema fwschema.Schema expected *tfsdk.Config expectedDiagnostics diag.Diagnostics }{ diff --git a/internal/fromproto6/configureprovider.go b/internal/fromproto6/configureprovider.go index 032ec668f..8efcd764e 100644 --- a/internal/fromproto6/configureprovider.go +++ b/internal/fromproto6/configureprovider.go @@ -4,14 +4,14 @@ import ( "context" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/provider" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-go/tfprotov6" ) // ConfigureProviderRequest returns the *fwserver.ConfigureProviderRequest // equivalent of a *tfprotov6.ConfigureProviderRequest. -func ConfigureProviderRequest(ctx context.Context, proto6 *tfprotov6.ConfigureProviderRequest, providerSchema *tfsdk.Schema) (*provider.ConfigureRequest, diag.Diagnostics) { +func ConfigureProviderRequest(ctx context.Context, proto6 *tfprotov6.ConfigureProviderRequest, providerSchema fwschema.Schema) (*provider.ConfigureRequest, diag.Diagnostics) { if proto6 == nil { return nil, nil } diff --git a/internal/fromproto6/configureprovider_test.go b/internal/fromproto6/configureprovider_test.go index 5d58070d5..40d1644b9 100644 --- a/internal/fromproto6/configureprovider_test.go +++ b/internal/fromproto6/configureprovider_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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/provider" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -44,7 +45,7 @@ func TestConfigureProviderRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov6.ConfigureProviderRequest - providerSchema *tfsdk.Schema + providerSchema fwschema.Schema expected *provider.ConfigureRequest expectedDiagnostics diag.Diagnostics }{ diff --git a/internal/fromproto6/importresourcestate.go b/internal/fromproto6/importresourcestate.go index 3d05bac58..09266037d 100644 --- a/internal/fromproto6/importresourcestate.go +++ b/internal/fromproto6/importresourcestate.go @@ -4,6 +4,7 @@ import ( "context" "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/tfsdk" @@ -13,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 *tfsdk.Schema) (*fwserver.ImportResourceStateRequest, diag.Diagnostics) { +func ImportResourceStateRequest(ctx context.Context, proto6 *tfprotov6.ImportResourceStateRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema) (*fwserver.ImportResourceStateRequest, diag.Diagnostics) { if proto6 == nil { return nil, nil } @@ -37,7 +38,7 @@ func ImportResourceStateRequest(ctx context.Context, proto6 *tfprotov6.ImportRes fw := &fwserver.ImportResourceStateRequest{ EmptyState: tfsdk.State{ Raw: tftypes.NewValue(resourceSchema.TerraformType(ctx), nil), - Schema: *resourceSchema, + Schema: tfsdkSchema(resourceSchema), }, ID: proto6.ID, ResourceType: resourceType, diff --git a/internal/fromproto6/importresourcestate_test.go b/internal/fromproto6/importresourcestate_test.go index 75f9a9a7a..8b5b8e71b 100644 --- a/internal/fromproto6/importresourcestate_test.go +++ b/internal/fromproto6/importresourcestate_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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" @@ -34,7 +35,7 @@ func TestImportResourceStateRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov6.ImportResourceStateRequest - resourceSchema *tfsdk.Schema + resourceSchema fwschema.Schema resourceType provider.ResourceType expected *fwserver.ImportResourceStateRequest expectedDiagnostics diag.Diagnostics diff --git a/internal/fromproto6/plan.go b/internal/fromproto6/plan.go index c38291f15..15848660f 100644 --- a/internal/fromproto6/plan.go +++ b/internal/fromproto6/plan.go @@ -4,13 +4,14 @@ import ( "context" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-go/tfprotov6" ) // Plan returns the *tfsdk.Plan for a *tfprotov6.DynamicValue and -// *tfsdk.Schema. -func Plan(ctx context.Context, proto6DynamicValue *tfprotov6.DynamicValue, schema *tfsdk.Schema) (*tfsdk.Plan, diag.Diagnostics) { +// fwschema.Schema. +func Plan(ctx context.Context, proto6DynamicValue *tfprotov6.DynamicValue, schema fwschema.Schema) (*tfsdk.Plan, diag.Diagnostics) { if proto6DynamicValue == nil { return nil, nil } @@ -46,7 +47,7 @@ func Plan(ctx context.Context, proto6DynamicValue *tfprotov6.DynamicValue, schem fw := &tfsdk.Plan{ Raw: proto6Value, - Schema: *schema, + Schema: tfsdkSchema(schema), } return fw, nil diff --git a/internal/fromproto6/plan_test.go b/internal/fromproto6/plan_test.go index b6b4ef8b4..bd60e22c4 100644 --- a/internal/fromproto6/plan_test.go +++ b/internal/fromproto6/plan_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-go/tfprotov6" @@ -52,7 +53,7 @@ func TestPlan(t *testing.T) { testCases := map[string]struct { input *tfprotov6.DynamicValue - schema *tfsdk.Schema + schema fwschema.Schema expected *tfsdk.Plan expectedDiagnostics diag.Diagnostics }{ diff --git a/internal/fromproto6/planresourcechange.go b/internal/fromproto6/planresourcechange.go index 921e0f0c3..9bb33f901 100644 --- a/internal/fromproto6/planresourcechange.go +++ b/internal/fromproto6/planresourcechange.go @@ -4,15 +4,15 @@ import ( "context" "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/tfsdk" "github.com/hashicorp/terraform-plugin-go/tfprotov6" ) // PlanResourceChangeRequest returns the *fwserver.PlanResourceChangeRequest // equivalent of a *tfprotov6.PlanResourceChangeRequest. -func PlanResourceChangeRequest(ctx context.Context, proto6 *tfprotov6.PlanResourceChangeRequest, resourceType provider.ResourceType, resourceSchema *tfsdk.Schema, providerMetaSchema *tfsdk.Schema) (*fwserver.PlanResourceChangeRequest, diag.Diagnostics) { +func PlanResourceChangeRequest(ctx context.Context, proto6 *tfprotov6.PlanResourceChangeRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.PlanResourceChangeRequest, diag.Diagnostics) { if proto6 == nil { return nil, nil } @@ -35,7 +35,7 @@ func PlanResourceChangeRequest(ctx context.Context, proto6 *tfprotov6.PlanResour fw := &fwserver.PlanResourceChangeRequest{ PriorPrivate: proto6.PriorPrivate, - ResourceSchema: *resourceSchema, + ResourceSchema: resourceSchema, ResourceType: resourceType, } diff --git a/internal/fromproto6/planresourcechange_test.go b/internal/fromproto6/planresourcechange_test.go index b0dad0982..c85598bad 100644 --- a/internal/fromproto6/planresourcechange_test.go +++ b/internal/fromproto6/planresourcechange_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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" @@ -45,9 +46,9 @@ func TestPlanResourceChangeRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov6.PlanResourceChangeRequest - resourceSchema *tfsdk.Schema + resourceSchema fwschema.Schema resourceType provider.ResourceType - providerMetaSchema *tfsdk.Schema + providerMetaSchema fwschema.Schema expected *fwserver.PlanResourceChangeRequest expectedDiagnostics diag.Diagnostics }{ @@ -93,7 +94,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { Raw: testProto6Value, Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "priorprivate": { @@ -103,7 +104,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { resourceSchema: testFwSchema, expected: &fwserver.PlanResourceChangeRequest{ PriorPrivate: []byte("{}"), - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "priorstate-missing-schema": { @@ -131,7 +132,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { Raw: testProto6Value, Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "proposednewstate-missing-schema": { @@ -159,7 +160,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { Raw: testProto6Value, Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "providermeta-missing-data": { @@ -171,7 +172,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { Raw: tftypes.NewValue(testProto6Type, nil), Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "providermeta-missing-schema": { @@ -181,7 +182,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { resourceSchema: testFwSchema, expected: &fwserver.PlanResourceChangeRequest{ // This intentionally should not include ProviderMeta - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "providermeta": { @@ -195,7 +196,7 @@ func TestPlanResourceChangeRequest(t *testing.T) { Raw: testProto6Value, Schema: *testFwSchema, }, - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, } diff --git a/internal/fromproto6/providermeta.go b/internal/fromproto6/providermeta.go index 47235871a..e28a63f87 100644 --- a/internal/fromproto6/providermeta.go +++ b/internal/fromproto6/providermeta.go @@ -4,18 +4,19 @@ import ( "context" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-go/tfprotov6" "github.com/hashicorp/terraform-plugin-go/tftypes" ) // ProviderMeta returns the *tfsdk.Config for a *tfprotov6.DynamicValue and -// *tfsdk.Schema. This data handling is different than Config to simplify +// fwschema.Schema. This data handling is different than Config to simplify // implementors, in that: // // - Missing Schema will return nil, rather than an error // - Missing DynamicValue will return nil typed Value, rather than an error -func ProviderMeta(ctx context.Context, proto6DynamicValue *tfprotov6.DynamicValue, schema *tfsdk.Schema) (*tfsdk.Config, diag.Diagnostics) { +func ProviderMeta(ctx context.Context, proto6DynamicValue *tfprotov6.DynamicValue, schema fwschema.Schema) (*tfsdk.Config, diag.Diagnostics) { if schema == nil { return nil, nil } @@ -24,7 +25,7 @@ func ProviderMeta(ctx context.Context, proto6DynamicValue *tfprotov6.DynamicValu fw := &tfsdk.Config{ Raw: tftypes.NewValue(schema.TerraformType(ctx), nil), - Schema: *schema, + Schema: tfsdkSchema(schema), } if proto6DynamicValue == nil { diff --git a/internal/fromproto6/providermeta_test.go b/internal/fromproto6/providermeta_test.go index 91a9cebc0..55c2c6a78 100644 --- a/internal/fromproto6/providermeta_test.go +++ b/internal/fromproto6/providermeta_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-go/tfprotov6" @@ -52,7 +53,7 @@ func TestProviderMeta(t *testing.T) { testCases := map[string]struct { input *tfprotov6.DynamicValue - schema *tfsdk.Schema + schema fwschema.Schema expected *tfsdk.Config expectedDiagnostics diag.Diagnostics }{ diff --git a/internal/fromproto6/readdatasource.go b/internal/fromproto6/readdatasource.go index 206ca759b..4459fc59d 100644 --- a/internal/fromproto6/readdatasource.go +++ b/internal/fromproto6/readdatasource.go @@ -4,15 +4,15 @@ import ( "context" "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/tfsdk" "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 *tfsdk.Schema, providerMetaSchema *tfsdk.Schema) (*fwserver.ReadDataSourceRequest, diag.Diagnostics) { +func ReadDataSourceRequest(ctx context.Context, proto6 *tfprotov6.ReadDataSourceRequest, dataSourceType provider.DataSourceType, dataSourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.ReadDataSourceRequest, diag.Diagnostics) { if proto6 == nil { return nil, nil } @@ -34,7 +34,7 @@ func ReadDataSourceRequest(ctx context.Context, proto6 *tfprotov6.ReadDataSource } fw := &fwserver.ReadDataSourceRequest{ - DataSourceSchema: *dataSourceSchema, + DataSourceSchema: dataSourceSchema, DataSourceType: dataSourceType, } diff --git a/internal/fromproto6/readdatasource_test.go b/internal/fromproto6/readdatasource_test.go index b18a022b0..778eebd22 100644 --- a/internal/fromproto6/readdatasource_test.go +++ b/internal/fromproto6/readdatasource_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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" @@ -45,9 +46,9 @@ func TestReadDataSourceRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov6.ReadDataSourceRequest - dataSourceSchema *tfsdk.Schema + dataSourceSchema fwschema.Schema dataSourceType provider.DataSourceType - providerMetaSchema *tfsdk.Schema + providerMetaSchema fwschema.Schema expected *fwserver.ReadDataSourceRequest expectedDiagnostics diag.Diagnostics }{ @@ -93,7 +94,7 @@ func TestReadDataSourceRequest(t *testing.T) { Raw: testProto6Value, Schema: *testFwSchema, }, - DataSourceSchema: *testFwSchema, + DataSourceSchema: testFwSchema, }, }, "providermeta-missing-data": { @@ -101,7 +102,7 @@ func TestReadDataSourceRequest(t *testing.T) { dataSourceSchema: testFwSchema, providerMetaSchema: testFwSchema, expected: &fwserver.ReadDataSourceRequest{ - DataSourceSchema: *testFwSchema, + DataSourceSchema: testFwSchema, ProviderMeta: &tfsdk.Config{ Raw: tftypes.NewValue(testProto6Type, nil), Schema: *testFwSchema, @@ -114,7 +115,7 @@ func TestReadDataSourceRequest(t *testing.T) { }, dataSourceSchema: testFwSchema, expected: &fwserver.ReadDataSourceRequest{ - DataSourceSchema: *testFwSchema, + DataSourceSchema: testFwSchema, // This intentionally should not include ProviderMeta }, }, @@ -125,7 +126,7 @@ func TestReadDataSourceRequest(t *testing.T) { dataSourceSchema: testFwSchema, providerMetaSchema: testFwSchema, expected: &fwserver.ReadDataSourceRequest{ - DataSourceSchema: *testFwSchema, + DataSourceSchema: testFwSchema, ProviderMeta: &tfsdk.Config{ Raw: testProto6Value, Schema: *testFwSchema, diff --git a/internal/fromproto6/readresource.go b/internal/fromproto6/readresource.go index 1a81f6272..f9d66a11e 100644 --- a/internal/fromproto6/readresource.go +++ b/internal/fromproto6/readresource.go @@ -4,15 +4,15 @@ import ( "context" "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/tfsdk" "github.com/hashicorp/terraform-plugin-go/tfprotov6" ) // ReadResourceRequest returns the *fwserver.ReadResourceRequest // equivalent of a *tfprotov6.ReadResourceRequest. -func ReadResourceRequest(ctx context.Context, proto6 *tfprotov6.ReadResourceRequest, resourceType provider.ResourceType, resourceSchema *tfsdk.Schema, providerMetaSchema *tfsdk.Schema) (*fwserver.ReadResourceRequest, diag.Diagnostics) { +func ReadResourceRequest(ctx context.Context, proto6 *tfprotov6.ReadResourceRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema, providerMetaSchema fwschema.Schema) (*fwserver.ReadResourceRequest, diag.Diagnostics) { if proto6 == nil { return nil, nil } diff --git a/internal/fromproto6/readresource_test.go b/internal/fromproto6/readresource_test.go index 7bc9ddf7d..431e6f893 100644 --- a/internal/fromproto6/readresource_test.go +++ b/internal/fromproto6/readresource_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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" @@ -45,9 +46,9 @@ func TestReadResourceRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov6.ReadResourceRequest - resourceSchema *tfsdk.Schema + resourceSchema fwschema.Schema resourceType provider.ResourceType - providerMetaSchema *tfsdk.Schema + providerMetaSchema fwschema.Schema expected *fwserver.ReadResourceRequest expectedDiagnostics diag.Diagnostics }{ diff --git a/internal/fromproto6/schema.go b/internal/fromproto6/schema.go new file mode 100644 index 000000000..d926c3b8e --- /dev/null +++ b/internal/fromproto6/schema.go @@ -0,0 +1,22 @@ +package fromproto6 + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" +) + +// tfsdkSchema is a temporary function that will return a given fwschema.Schema +// as tfsdk.Schema or panic. This will be removed once tfsdk.Config, +// tfsdk.Plan, and tfsdk.State no longer use tfsdk.Schema directly or are +// replaced. +// 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 + default: + panic(fmt.Sprintf("unknown fromproto6 fwschema.Schema type: %T", s)) + } +} diff --git a/internal/fromproto6/state.go b/internal/fromproto6/state.go index 2a6ee66b9..0b56e620b 100644 --- a/internal/fromproto6/state.go +++ b/internal/fromproto6/state.go @@ -4,13 +4,14 @@ import ( "context" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-go/tfprotov6" ) // State returns the *tfsdk.State for a *tfprotov6.DynamicValue and -// *tfsdk.Schema. -func State(ctx context.Context, proto6DynamicValue *tfprotov6.DynamicValue, schema *tfsdk.Schema) (*tfsdk.State, diag.Diagnostics) { +// fwschema.Schema. +func State(ctx context.Context, proto6DynamicValue *tfprotov6.DynamicValue, schema fwschema.Schema) (*tfsdk.State, diag.Diagnostics) { if proto6DynamicValue == nil { return nil, nil } @@ -46,7 +47,7 @@ func State(ctx context.Context, proto6DynamicValue *tfprotov6.DynamicValue, sche fw := &tfsdk.State{ Raw: proto6Value, - Schema: *schema, + Schema: tfsdkSchema(schema), } return fw, nil diff --git a/internal/fromproto6/state_test.go b/internal/fromproto6/state_test.go index 93eca44c6..016665bff 100644 --- a/internal/fromproto6/state_test.go +++ b/internal/fromproto6/state_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-go/tfprotov6" @@ -52,7 +53,7 @@ func TestState(t *testing.T) { testCases := map[string]struct { input *tfprotov6.DynamicValue - schema *tfsdk.Schema + schema fwschema.Schema expected *tfsdk.State expectedDiagnostics diag.Diagnostics }{ diff --git a/internal/fromproto6/upgraderesourcestate.go b/internal/fromproto6/upgraderesourcestate.go index 22d328fb3..0b9e034e9 100644 --- a/internal/fromproto6/upgraderesourcestate.go +++ b/internal/fromproto6/upgraderesourcestate.go @@ -4,15 +4,15 @@ import ( "context" "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/tfsdk" "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 *tfsdk.Schema) (*fwserver.UpgradeResourceStateRequest, diag.Diagnostics) { +func UpgradeResourceStateRequest(ctx context.Context, proto6 *tfprotov6.UpgradeResourceStateRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema) (*fwserver.UpgradeResourceStateRequest, diag.Diagnostics) { if proto6 == nil { return nil, nil } @@ -35,7 +35,7 @@ func UpgradeResourceStateRequest(ctx context.Context, proto6 *tfprotov6.UpgradeR fw := &fwserver.UpgradeResourceStateRequest{ RawState: proto6.RawState, - ResourceSchema: *resourceSchema, + ResourceSchema: resourceSchema, ResourceType: resourceType, Version: proto6.Version, } diff --git a/internal/fromproto6/upgraderesourcestate_test.go b/internal/fromproto6/upgraderesourcestate_test.go index ea880987a..0366b0355 100644 --- a/internal/fromproto6/upgraderesourcestate_test.go +++ b/internal/fromproto6/upgraderesourcestate_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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" @@ -28,7 +29,7 @@ func TestUpgradeResourceStateRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov6.UpgradeResourceStateRequest - resourceSchema *tfsdk.Schema + resourceSchema fwschema.Schema resourceType provider.ResourceType expected *fwserver.UpgradeResourceStateRequest expectedDiagnostics diag.Diagnostics @@ -48,14 +49,14 @@ func TestUpgradeResourceStateRequest(t *testing.T) { RawState: testNewRawState(t, map[string]interface{}{ "test_attribute": "test-value", }), - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "resourceschema": { input: &tfprotov6.UpgradeResourceStateRequest{}, resourceSchema: testFwSchema, expected: &fwserver.UpgradeResourceStateRequest{ - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, }, }, "resourceschema-missing": { @@ -77,7 +78,7 @@ func TestUpgradeResourceStateRequest(t *testing.T) { }, resourceSchema: testFwSchema, expected: &fwserver.UpgradeResourceStateRequest{ - ResourceSchema: *testFwSchema, + ResourceSchema: testFwSchema, Version: 123, }, }, diff --git a/internal/fromproto6/validatedatasourceconfig.go b/internal/fromproto6/validatedatasourceconfig.go index 6b2edbaa6..adca93076 100644 --- a/internal/fromproto6/validatedatasourceconfig.go +++ b/internal/fromproto6/validatedatasourceconfig.go @@ -4,15 +4,15 @@ import ( "context" "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/tfsdk" "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 *tfsdk.Schema) (*fwserver.ValidateDataSourceConfigRequest, diag.Diagnostics) { +func ValidateDataSourceConfigRequest(ctx context.Context, proto6 *tfprotov6.ValidateDataResourceConfigRequest, dataSourceType provider.DataSourceType, dataSourceSchema fwschema.Schema) (*fwserver.ValidateDataSourceConfigRequest, diag.Diagnostics) { if proto6 == nil { return nil, nil } diff --git a/internal/fromproto6/validatedatasourceconfig_test.go b/internal/fromproto6/validatedatasourceconfig_test.go index 6c514ccba..b21f9b73a 100644 --- a/internal/fromproto6/validatedatasourceconfig_test.go +++ b/internal/fromproto6/validatedatasourceconfig_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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" @@ -45,7 +46,7 @@ func TestValidateDataSourceConfigRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov6.ValidateDataResourceConfigRequest - dataSourceSchema *tfsdk.Schema + dataSourceSchema fwschema.Schema dataSourceType provider.DataSourceType expected *fwserver.ValidateDataSourceConfigRequest expectedDiagnostics diag.Diagnostics diff --git a/internal/fromproto6/validateproviderconfig.go b/internal/fromproto6/validateproviderconfig.go index 7d24c02af..09bd0e120 100644 --- a/internal/fromproto6/validateproviderconfig.go +++ b/internal/fromproto6/validateproviderconfig.go @@ -4,14 +4,14 @@ import ( "context" "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/tfsdk" "github.com/hashicorp/terraform-plugin-go/tfprotov6" ) // ValidateProviderConfigRequest returns the *fwserver.ValidateProviderConfigRequest // equivalent of a *tfprotov6.ValidateProviderConfigRequest. -func ValidateProviderConfigRequest(ctx context.Context, proto6 *tfprotov6.ValidateProviderConfigRequest, providerSchema *tfsdk.Schema) (*fwserver.ValidateProviderConfigRequest, diag.Diagnostics) { +func ValidateProviderConfigRequest(ctx context.Context, proto6 *tfprotov6.ValidateProviderConfigRequest, providerSchema fwschema.Schema) (*fwserver.ValidateProviderConfigRequest, diag.Diagnostics) { if proto6 == nil { return nil, nil } diff --git a/internal/fromproto6/validateproviderconfig_test.go b/internal/fromproto6/validateproviderconfig_test.go index 67e255879..17323d2e1 100644 --- a/internal/fromproto6/validateproviderconfig_test.go +++ b/internal/fromproto6/validateproviderconfig_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -44,7 +45,7 @@ func TestValidateProviderConfigRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov6.ValidateProviderConfigRequest - providerSchema *tfsdk.Schema + providerSchema fwschema.Schema expected *fwserver.ValidateProviderConfigRequest expectedDiagnostics diag.Diagnostics }{ diff --git a/internal/fromproto6/validateresourceconfig.go b/internal/fromproto6/validateresourceconfig.go index a3bc39b32..65c763f30 100644 --- a/internal/fromproto6/validateresourceconfig.go +++ b/internal/fromproto6/validateresourceconfig.go @@ -4,15 +4,15 @@ import ( "context" "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/tfsdk" "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 *tfsdk.Schema) (*fwserver.ValidateResourceConfigRequest, diag.Diagnostics) { +func ValidateResourceConfigRequest(ctx context.Context, proto6 *tfprotov6.ValidateResourceConfigRequest, resourceType provider.ResourceType, resourceSchema fwschema.Schema) (*fwserver.ValidateResourceConfigRequest, diag.Diagnostics) { if proto6 == nil { return nil, nil } diff --git a/internal/fromproto6/validateresourceconfig_test.go b/internal/fromproto6/validateresourceconfig_test.go index befeed53c..7b834b985 100644 --- a/internal/fromproto6/validateresourceconfig_test.go +++ b/internal/fromproto6/validateresourceconfig_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "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" @@ -45,7 +46,7 @@ func TestValidateResourceConfigRequest(t *testing.T) { testCases := map[string]struct { input *tfprotov6.ValidateResourceConfigRequest - resourceSchema *tfsdk.Schema + resourceSchema fwschema.Schema resourceType provider.ResourceType expected *fwserver.ValidateResourceConfigRequest expectedDiagnostics diag.Diagnostics diff --git a/internal/fwschema/attribute.go b/internal/fwschema/attribute.go new file mode 100644 index 000000000..4ccfae86a --- /dev/null +++ b/internal/fwschema/attribute.go @@ -0,0 +1,69 @@ +package fwschema + +import ( + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +// Attribute is the core interface required for implementing Terraform schema +// functionality that can accept a value. This is intended to be the first +// abstraction of tfsdk.Attribute functionality into data source, provider, +// and resource specific functionality. +// +// Refer to the internal/fwschema/fwxschema package for optional interfaces +// that define framework-specific functionality, such a plan modification and +// validation. +type Attribute interface { + // Implementations should include the tftypes.AttributePathStepper + // interface methods for proper path and data handling. + tftypes.AttributePathStepper + + // Equal should return true if the other attribute is exactly equivalent. + Equal(o Attribute) bool + + // GetAttributes should return the nested attributes of an attribute, if + // applicable. This is named differently than Attribute to prevent a + // conflict with the tfsdk.Attribute field name. + GetAttributes() NestedAttributes + + // GetDeprecationMessage should return a non-empty string if an attribute + // is deprecated. This is named differently than DeprecationMessage to + // prevent a conflict with the tfsdk.Attribute field name. + GetDeprecationMessage() string + + // GetDescription should return a non-empty string if an attribute + // has a plaintext description. This is named differently than Description + // to prevent a conflict with the tfsdk.Attribute field name. + GetDescription() string + + // GetMarkdownDescription should return a non-empty string if an attribute + // has a Markdown description. This is named differently than + // MarkdownDescription to prevent a conflict with the tfsdk.Attribute field + // name. + GetMarkdownDescription() string + + // GetType should return the framework type of an attribute. This is named + // differently than Type to prevent a conflict with the tfsdk.Attribute + // field name. + GetType() attr.Type + + // IsComputed should return true if the attribute configuration value is + // computed. This is named differently than Computed to prevent a conflict + // with the tfsdk.Attribute field name. + IsComputed() bool + + // IsOptional should return true if the attribute configuration value is + // optional. This is named differently than Optional to prevent a conflict + // with the tfsdk.Attribute field name. + IsOptional() bool + + // IsRequired should return true if the attribute configuration value is + // required. This is named differently than Required to prevent a conflict + // with the tfsdk.Attribute field name. + IsRequired() bool + + // IsSensitive should return true if the attribute configuration value is + // sensitive. This is named differently than Sensitive to prevent a + // conflict with the tfsdk.Attribute field name. + IsSensitive() bool +} diff --git a/internal/fwschema/block.go b/internal/fwschema/block.go new file mode 100644 index 000000000..0ee4e8672 --- /dev/null +++ b/internal/fwschema/block.go @@ -0,0 +1,67 @@ +package fwschema + +import ( + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +// Block is the core interface required for implementing Terraform schema +// functionality that structurally holds attributes and blocks. This is +// intended to be the first abstraction of tfsdk.Block functionality into +// data source, provider, and resource specific functionality. +// +// Refer to the internal/fwschema/fwxschema package for optional interfaces +// that define framework-specific functionality, such a plan modification and +// validation. +type Block interface { + // Implementations should include the tftypes.AttributePathStepper + // interface methods for proper path and data handling. + tftypes.AttributePathStepper + + // Equal should return true if the other block is exactly equivalent. + Equal(o Block) bool + + // GetAttributes should return the nested attributes of a block, if + // applicable. This is named differently than Attributes to prevent a + // conflict with the tfsdk.Block field name. + GetAttributes() map[string]Attribute + + // GetBlocks should return the nested blocks of a block, if + // applicable. This is named differently than Blocks to prevent a + // conflict with the tfsdk.Block field name. + GetBlocks() map[string]Block + + // GetDeprecationMessage should return a non-empty string if an attribute + // is deprecated. This is named differently than DeprecationMessage to + // prevent a conflict with the tfsdk.Attribute field name. + GetDeprecationMessage() string + + // GetDescription should return a non-empty string if an attribute + // has a plaintext description. This is named differently than Description + // to prevent a conflict with the tfsdk.Attribute field name. + GetDescription() string + + // GetMarkdownDescription should return a non-empty string if an attribute + // has a Markdown description. This is named differently than + // MarkdownDescription to prevent a conflict with the tfsdk.Attribute field + // name. + GetMarkdownDescription() string + + // GetMaxItems should return the max items of a block. This is named + // differently than MaxItems to prevent a conflict with the tfsdk.Block + // field name. + GetMaxItems() int64 + + // GetMinItems should return the min items of a block. This is named + // differently than MinItems to prevent a conflict with the tfsdk.Block + // field name. + GetMinItems() int64 + + // GetNestingMode should return the nesting mode of a block. This is named + // differently than NestingMode to prevent a conflict with the tfsdk.Block + // field name. + GetNestingMode() BlockNestingMode + + // Type should return the framework type of a block. + Type() attr.Type +} diff --git a/internal/fwschema/block_nested_mode.go b/internal/fwschema/block_nested_mode.go new file mode 100644 index 000000000..5206b3024 --- /dev/null +++ b/internal/fwschema/block_nested_mode.go @@ -0,0 +1,26 @@ +package fwschema + +// BlockNestingMode is an enum type of the ways attributes and blocks can be +// nested in a block. They can be a list or a set. +// +// While the protocol and theoretically Terraform itself support map, single, +// and group nesting modes, this framework intentionally only supports list +// and set blocks as those other modes were not typically implemented or +// tested since the older Terraform Plugin SDK did not support them. +type BlockNestingMode uint8 + +const ( + // BlockNestingModeUnknown is an invalid nesting mode, used to catch when a + // nesting mode is expected and not set. + BlockNestingModeUnknown BlockNestingMode = 0 + + // BlockNestingModeList is for attributes that represent a list of objects, + // with multiple instances of those attributes nested inside a list + // under another attribute. + BlockNestingModeList BlockNestingMode = 1 + + // BlockNestingModeSet is for attributes that represent a set of objects, + // with multiple, unique instances of those attributes nested inside a + // set under another attribute. + BlockNestingModeSet BlockNestingMode = 2 +) diff --git a/internal/fwschema/doc.go b/internal/fwschema/doc.go new file mode 100644 index 000000000..35f544904 --- /dev/null +++ b/internal/fwschema/doc.go @@ -0,0 +1,7 @@ +// Package fwschema implements shared logic for describing the structure, +// data types, and behaviors of framework data for data sources, providers, +// and resources. +// +// Refer to the internal/fwschemadata package for logic built on values based +// on this schema information. +package fwschema diff --git a/internal/fwschema/fwxschema/attribute_plan_modification.go b/internal/fwschema/fwxschema/attribute_plan_modification.go new file mode 100644 index 000000000..50a6ccbdb --- /dev/null +++ b/internal/fwschema/fwxschema/attribute_plan_modification.go @@ -0,0 +1,19 @@ +package fwxschema + +import ( + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" +) + +// AttributeWithPlanModifiers is an optional interface on Attribute which enables +// plan modification support. +type AttributeWithPlanModifiers interface { + // Implementations should include the fwschema.Attribute interface methods + // for proper attribute handling. + fwschema.Attribute + + // GetPlanModifiers should return a list of attribute-based plan modifiers. + // This is named differently than PlanModifiers to prevent a conflict with + // the tfsdk.Attribute field name. + GetPlanModifiers() tfsdk.AttributePlanModifiers +} diff --git a/internal/fwschema/fwxschema/attribute_validation.go b/internal/fwschema/fwxschema/attribute_validation.go new file mode 100644 index 000000000..f75b76773 --- /dev/null +++ b/internal/fwschema/fwxschema/attribute_validation.go @@ -0,0 +1,19 @@ +package fwxschema + +import ( + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" +) + +// AttributeWithValidators is an optional interface on Attribute which enables +// validation support. +type AttributeWithValidators interface { + // Implementations should include the fwschema.Attribute interface methods + // for proper attribute handling. + fwschema.Attribute + + // GetValidators should return a list of attribute-based validators. This + // is named differently than PlanModifiers to prevent a conflict with the + // tfsdk.Attribute field name. + GetValidators() []tfsdk.AttributeValidator +} diff --git a/internal/fwschema/fwxschema/block_plan_modification.go b/internal/fwschema/fwxschema/block_plan_modification.go new file mode 100644 index 000000000..330f026e0 --- /dev/null +++ b/internal/fwschema/fwxschema/block_plan_modification.go @@ -0,0 +1,19 @@ +package fwxschema + +import ( + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" +) + +// BlockWithPlanModifiers is an optional interface on Block which enables +// plan modification support. +type BlockWithPlanModifiers interface { + // Implementations should include the fwschema.Block interface methods + // for proper block handling. + fwschema.Block + + // GetPlanModifiers should return a list of attribute-based plan modifiers. + // This is named differently than PlanModifiers to prevent a conflict with + // the tfsdk.Block field name. + GetPlanModifiers() tfsdk.AttributePlanModifiers +} diff --git a/internal/fwschema/fwxschema/block_validation.go b/internal/fwschema/fwxschema/block_validation.go new file mode 100644 index 000000000..7dfd8a250 --- /dev/null +++ b/internal/fwschema/fwxschema/block_validation.go @@ -0,0 +1,19 @@ +package fwxschema + +import ( + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" +) + +// BlockWithValidators is an optional interface on Block which enables +// validation support. +type BlockWithValidators interface { + // Implementations should include the fwschema.Block interface methods + // for proper block handling. + fwschema.Block + + // GetValidators should return a list of attribute-based validators. This + // is named differently than Validators to prevent a conflict with the + // tfsdk.Block field name. + GetValidators() []tfsdk.AttributeValidator +} diff --git a/internal/fwschema/fwxschema/doc.go b/internal/fwschema/fwxschema/doc.go new file mode 100644 index 000000000..ade502876 --- /dev/null +++ b/internal/fwschema/fwxschema/doc.go @@ -0,0 +1,6 @@ +// Package fwxschema implements extra framework-based schema +// functionality on top of base Terraform attribute functionality. +// +// This package is separated from fwschema to prevent import cycles +// with existing tfsdk functionality. +package fwxschema diff --git a/internal/fwschema/nested_attributes.go b/internal/fwschema/nested_attributes.go new file mode 100644 index 000000000..a5823a3d1 --- /dev/null +++ b/internal/fwschema/nested_attributes.go @@ -0,0 +1,297 @@ +package fwschema + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +// NestingMode is an enum type of the ways nested attributes can be nested in +// an attribute. They can be a list, a set, a map (with string +// keys), or they can be nested directly, like an object. +type NestingMode uint8 + +const ( + // NestingModeUnknown is an invalid nesting mode, used to catch when a + // nesting mode is expected and not set. + NestingModeUnknown NestingMode = 0 + + // NestingModeSingle is for attributes that represent a struct or + // object, a single instance of those attributes directly nested under + // another attribute. + NestingModeSingle NestingMode = 1 + + // NestingModeList is for attributes that represent a list of objects, + // with multiple instances of those attributes nested inside a list + // under another attribute. + NestingModeList NestingMode = 2 + + // NestingModeSet is for attributes that represent a set of objects, + // with multiple, unique instances of those attributes nested inside a + // set under another attribute. + NestingModeSet NestingMode = 3 + + // NestingModeMap is for attributes that represent a map of objects, + // with multiple instances of those attributes, each associated with a + // unique string key, nested inside a map under another attribute. + NestingModeMap NestingMode = 4 +) + +// NestedAttributes surfaces a group of attributes to nest beneath another +// attribute, and how that nesting should behave. Nesting can have the +// following modes: +// +// * SingleNestedAttributes are nested attributes that represent a struct or +// object; there should only be one instance of them nested beneath that +// specific attribute. +// +// * ListNestedAttributes are nested attributes that represent a list of +// structs or objects; there can be multiple instances of them beneath that +// specific attribute. +// +// * SetNestedAttributes are nested attributes that represent a set of structs +// or objects; there can be multiple instances of them beneath that specific +// attribute. Unlike ListNestedAttributes, these nested attributes must have +// unique values. +// +// * MapNestedAttributes are nested attributes that represent a string-indexed +// map of structs or objects; there can be multiple instances of them beneath +// that specific attribute. Unlike ListNestedAttributes, these nested +// attributes must be associated with a unique key. Unlike SetNestedAttributes, +// the key must be explicitly set by the user. +type NestedAttributes interface { + tftypes.AttributePathStepper + AttributeType() attr.Type + GetNestingMode() NestingMode + GetAttributes() map[string]Attribute + Equal(NestedAttributes) bool +} + +type UnderlyingAttributes map[string]Attribute + +func (n UnderlyingAttributes) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (interface{}, error) { + a, ok := step.(tftypes.AttributeName) + + if !ok { + return nil, fmt.Errorf("can't apply %T to Attributes", step) + } + + res, ok := n[string(a)] + + if !ok { + return nil, fmt.Errorf("no attribute %q on Attributes", a) + } + + return res, nil +} + +// AttributeType returns an attr.Type corresponding to the nested attributes. +func (n UnderlyingAttributes) AttributeType() attr.Type { + attrTypes := map[string]attr.Type{} + for name, attr := range n { + if attr.GetType() != nil { + attrTypes[name] = attr.GetType() + } + if attr.GetAttributes() != nil { + attrTypes[name] = attr.GetAttributes().AttributeType() + } + } + return types.ObjectType{ + AttrTypes: attrTypes, + } +} + +type SingleNestedAttributes struct { + UnderlyingAttributes +} + +func (s SingleNestedAttributes) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (interface{}, error) { + a, ok := step.(tftypes.AttributeName) + + if !ok { + return nil, fmt.Errorf("can't apply %T to Attributes", step) + } + + res, ok := s.UnderlyingAttributes[string(a)] + + if !ok { + return nil, fmt.Errorf("no attribute %q on Attributes", a) + } + + return res, nil +} + +func (s SingleNestedAttributes) AttributeType() attr.Type { + return s.UnderlyingAttributes.AttributeType() +} + +func (s SingleNestedAttributes) GetAttributes() map[string]Attribute { + return s.UnderlyingAttributes +} + +func (s SingleNestedAttributes) GetNestingMode() NestingMode { + return NestingModeSingle +} + +func (s SingleNestedAttributes) Equal(o NestedAttributes) bool { + other, ok := o.(SingleNestedAttributes) + if !ok { + return false + } + if len(other.UnderlyingAttributes) != len(s.UnderlyingAttributes) { + return false + } + for k, v := range s.UnderlyingAttributes { + otherV, ok := other.UnderlyingAttributes[k] + if !ok { + return false + } + if !v.Equal(otherV) { + return false + } + } + return true +} + +type ListNestedAttributes struct { + UnderlyingAttributes +} + +func (l ListNestedAttributes) GetAttributes() map[string]Attribute { + return l.UnderlyingAttributes +} + +func (l ListNestedAttributes) GetNestingMode() NestingMode { + return NestingModeList +} + +// AttributeType returns an attr.Type corresponding to the nested attributes. +func (l ListNestedAttributes) AttributeType() attr.Type { + return types.ListType{ + ElemType: l.UnderlyingAttributes.AttributeType(), + } +} + +func (l ListNestedAttributes) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (interface{}, error) { + _, ok := step.(tftypes.ElementKeyInt) + if !ok { + return nil, fmt.Errorf("can't apply %T to ListNestedAttributes", step) + } + return l.UnderlyingAttributes, nil +} + +func (l ListNestedAttributes) Equal(o NestedAttributes) bool { + other, ok := o.(ListNestedAttributes) + if !ok { + return false + } + if len(other.UnderlyingAttributes) != len(l.UnderlyingAttributes) { + return false + } + for k, v := range l.UnderlyingAttributes { + otherV, ok := other.UnderlyingAttributes[k] + if !ok { + return false + } + if !v.Equal(otherV) { + return false + } + } + return true +} + +type SetNestedAttributes struct { + UnderlyingAttributes +} + +func (s SetNestedAttributes) GetAttributes() map[string]Attribute { + return s.UnderlyingAttributes +} + +func (s SetNestedAttributes) GetNestingMode() NestingMode { + return NestingModeSet +} + +// AttributeType returns an attr.Type corresponding to the nested attributes. +func (s SetNestedAttributes) AttributeType() attr.Type { + return types.SetType{ + ElemType: s.UnderlyingAttributes.AttributeType(), + } +} + +func (s SetNestedAttributes) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (interface{}, error) { + _, ok := step.(tftypes.ElementKeyValue) + if !ok { + return nil, fmt.Errorf("can't use %T on sets", step) + } + return s.UnderlyingAttributes, nil +} + +func (s SetNestedAttributes) Equal(o NestedAttributes) bool { + other, ok := o.(SetNestedAttributes) + if !ok { + return false + } + if len(other.UnderlyingAttributes) != len(s.UnderlyingAttributes) { + return false + } + for k, v := range s.UnderlyingAttributes { + otherV, ok := other.UnderlyingAttributes[k] + if !ok { + return false + } + if !v.Equal(otherV) { + return false + } + } + return true +} + +type MapNestedAttributes struct { + UnderlyingAttributes +} + +func (m MapNestedAttributes) GetAttributes() map[string]Attribute { + return m.UnderlyingAttributes +} + +func (m MapNestedAttributes) GetNestingMode() NestingMode { + return NestingModeMap +} + +// AttributeType returns an attr.Type corresponding to the nested attributes. +func (m MapNestedAttributes) AttributeType() attr.Type { + return types.MapType{ + ElemType: m.UnderlyingAttributes.AttributeType(), + } +} + +func (m MapNestedAttributes) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (interface{}, error) { + _, ok := step.(tftypes.ElementKeyString) + if !ok { + return nil, fmt.Errorf("can't use %T on maps", step) + } + return m.UnderlyingAttributes, nil +} + +func (m MapNestedAttributes) Equal(o NestedAttributes) bool { + other, ok := o.(MapNestedAttributes) + if !ok { + return false + } + if len(other.UnderlyingAttributes) != len(m.UnderlyingAttributes) { + return false + } + for k, v := range m.UnderlyingAttributes { + otherV, ok := other.UnderlyingAttributes[k] + if !ok { + return false + } + if !v.Equal(otherV) { + return false + } + } + return true +} diff --git a/internal/fwschema/nested_block.go b/internal/fwschema/nested_block.go new file mode 100644 index 000000000..5d49e37e8 --- /dev/null +++ b/internal/fwschema/nested_block.go @@ -0,0 +1,33 @@ +package fwschema + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +type NestedBlock struct { + Block +} + +// ApplyTerraform5AttributePathStep allows Blocks to be walked using +// tftypes.Walk and tftypes.Transform. +func (b NestedBlock) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (interface{}, error) { + a, ok := step.(tftypes.AttributeName) + + if !ok { + return nil, fmt.Errorf("can't apply %T to block", step) + } + + attrName := string(a) + + if attr, ok := b.Block.GetAttributes()[attrName]; ok { + return attr, nil + } + + if block, ok := b.Block.GetBlocks()[attrName]; ok { + return block, nil + } + + return nil, fmt.Errorf("no attribute %q on Attributes or Blocks", a) +} diff --git a/internal/fwschema/schema.go b/internal/fwschema/schema.go new file mode 100644 index 000000000..5826449fd --- /dev/null +++ b/internal/fwschema/schema.go @@ -0,0 +1,78 @@ +package fwschema + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +// Schema is the core interface required for data sources, providers, and +// resources. +type Schema interface { + // Implementations should include the tftypes.AttributePathStepper + // interface methods for proper path and data handling. + tftypes.AttributePathStepper + + // AttributeAtPath should return the Attribute at the given path or return + // an error. This signature matches the existing tfsdk.Schema type + // AttributeAtPath method signature to prevent the need for a breaking + // change or deprecation of that method to create this interface. + AttributeAtPath(path *tftypes.AttributePath) (Attribute, error) + + // AttributeType should return the framework type of the schema. This is + // named differently than the Attribute interface GetType method name to + // match the existing tfsdk.Schema type AttributeType method signature and + // to prevent the need for a breaking change or deprecation of that method + // to create this interface. + AttributeType() attr.Type + + // AttributeTypeAtPath should return the framework type of the Attribute at + // the given path or return an error. This signature matches the existing + // tfsdk.Schema type AttributeAtPath method signature to prevent the need + // for a breaking change or deprecation of that method to create this + // interface. + // + // This will likely be removed in the future in preference of + // AttributeAtPath. + AttributeTypeAtPath(path *tftypes.AttributePath) (attr.Type, error) + + // GetAttributes should return the attributes of a schema. This is named + // differently than Attributes to prevent a conflict with the tfsdk.Schema + // field name. + GetAttributes() map[string]Attribute + + // GetBlocks should return the blocks of a schema. This is named + // differently than Blocks to prevent a conflict with the tfsdk.Schema + // field name. + GetBlocks() map[string]Block + + // GetDeprecationMessage should return a non-empty string if a schema + // is deprecated. This is named differently than DeprecationMessage to + // prevent a conflict with the tfsdk.Schema field name. + GetDeprecationMessage() string + + // GetDescription should return a non-empty string if a schema has a + // plaintext description. This is named differently than Description + // to prevent a conflict with the tfsdk.Schema field name. + GetDescription() string + + // GetMarkdownDescription should return a non-empty string if a schema has + // a Markdown description. This is named differently than + // MarkdownDescription to prevent a conflict with the tfsdk.Schema field + // name. + GetMarkdownDescription() string + + // GetVersion should return the version of a schema. This is named + // differently than Version to prevent a conflict with the tfsdk.Schema + // field name. + GetVersion() int64 + + // TerraformType should return the Terraform type of the schema. This + // signature matches the existing tfsdk.Schema type TerraformType method + // signature to prevent the need for a breaking change or deprecation of + // that method to create this interface. + // + // This will likely be removed in the future in preferene of AttributeType. + TerraformType(ctx context.Context) tftypes.Type +} diff --git a/internal/fwserver/attribute_plan_modification.go b/internal/fwserver/attribute_plan_modification.go index 775963a64..7b8839952 100644 --- a/internal/fwserver/attribute_plan_modification.go +++ b/internal/fwserver/attribute_plan_modification.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema/fwxschema" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -15,7 +17,7 @@ import ( // The extra Attribute parameter is a carry-over of creating the proto6server // package from the tfsdk package and not wanting to export the method. // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/365 -func AttributeModifyPlan(ctx context.Context, a tfsdk.Attribute, req tfsdk.ModifyAttributePlanRequest, resp *ModifySchemaPlanResponse) { +func AttributeModifyPlan(ctx context.Context, a fwschema.Attribute, req tfsdk.ModifyAttributePlanRequest, resp *ModifySchemaPlanResponse) { ctx = logging.FrameworkWithAttributePath(ctx, req.AttributePath.String()) attrConfig, diags := ConfigGetAttributeValue(ctx, req.Config, req.AttributePath) @@ -46,35 +48,38 @@ func AttributeModifyPlan(ctx context.Context, a tfsdk.Attribute, req tfsdk.Modif req.AttributePlan = attrPlan var requiresReplace bool - for _, planModifier := range a.PlanModifiers { - modifyResp := &tfsdk.ModifyAttributePlanResponse{ - AttributePlan: req.AttributePlan, - RequiresReplace: requiresReplace, - } - logging.FrameworkDebug( - ctx, - "Calling provider defined AttributePlanModifier", - map[string]interface{}{ - logging.KeyDescription: planModifier.Description(ctx), - }, - ) - planModifier.Modify(ctx, req, modifyResp) - logging.FrameworkDebug( - ctx, - "Called provider defined AttributePlanModifier", - map[string]interface{}{ - logging.KeyDescription: planModifier.Description(ctx), - }, - ) + if attributeWithPlanModifiers, ok := a.(fwxschema.AttributeWithPlanModifiers); ok { + for _, planModifier := range attributeWithPlanModifiers.GetPlanModifiers() { + modifyResp := &tfsdk.ModifyAttributePlanResponse{ + AttributePlan: req.AttributePlan, + RequiresReplace: requiresReplace, + } - req.AttributePlan = modifyResp.AttributePlan - resp.Diagnostics.Append(modifyResp.Diagnostics...) - requiresReplace = modifyResp.RequiresReplace + logging.FrameworkDebug( + ctx, + "Calling provider defined AttributePlanModifier", + map[string]interface{}{ + logging.KeyDescription: planModifier.Description(ctx), + }, + ) + planModifier.Modify(ctx, req, modifyResp) + logging.FrameworkDebug( + ctx, + "Called provider defined AttributePlanModifier", + map[string]interface{}{ + logging.KeyDescription: planModifier.Description(ctx), + }, + ) - // Only on new errors. - if modifyResp.Diagnostics.HasError() { - return + req.AttributePlan = modifyResp.AttributePlan + resp.Diagnostics.Append(modifyResp.Diagnostics...) + requiresReplace = modifyResp.RequiresReplace + + // Only on new errors. + if modifyResp.Diagnostics.HasError() { + return + } } } @@ -89,13 +94,13 @@ func AttributeModifyPlan(ctx context.Context, a tfsdk.Attribute, req tfsdk.Modif return } - if a.Attributes == nil || len(a.Attributes.GetAttributes()) == 0 { + if a.GetAttributes() == nil || len(a.GetAttributes().GetAttributes()) == 0 { return } - nm := a.Attributes.GetNestingMode() + nm := a.GetAttributes().GetNestingMode() switch nm { - case tfsdk.NestingModeList: + case fwschema.NestingModeList: l, ok := req.AttributePlan.(types.List) if !ok { @@ -110,7 +115,7 @@ func AttributeModifyPlan(ctx context.Context, a tfsdk.Attribute, req tfsdk.Modif } for idx := range l.Elems { - for name, attr := range a.Attributes.GetAttributes() { + for name, attr := range a.GetAttributes().GetAttributes() { attrReq := tfsdk.ModifyAttributePlanRequest{ AttributePath: req.AttributePath.AtListIndex(idx).AtName(name), Config: req.Config, @@ -122,7 +127,7 @@ func AttributeModifyPlan(ctx context.Context, a tfsdk.Attribute, req tfsdk.Modif AttributeModifyPlan(ctx, attr, attrReq, resp) } } - case tfsdk.NestingModeSet: + case fwschema.NestingModeSet: s, ok := req.AttributePlan.(types.Set) if !ok { @@ -137,7 +142,7 @@ func AttributeModifyPlan(ctx context.Context, a tfsdk.Attribute, req tfsdk.Modif } for _, value := range s.Elems { - for name, attr := range a.Attributes.GetAttributes() { + for name, attr := range a.GetAttributes().GetAttributes() { attrReq := tfsdk.ModifyAttributePlanRequest{ AttributePath: req.AttributePath.AtSetValue(value).AtName(name), Config: req.Config, @@ -149,7 +154,7 @@ func AttributeModifyPlan(ctx context.Context, a tfsdk.Attribute, req tfsdk.Modif AttributeModifyPlan(ctx, attr, attrReq, resp) } } - case tfsdk.NestingModeMap: + case fwschema.NestingModeMap: m, ok := req.AttributePlan.(types.Map) if !ok { @@ -164,7 +169,7 @@ func AttributeModifyPlan(ctx context.Context, a tfsdk.Attribute, req tfsdk.Modif } for key := range m.Elems { - for name, attr := range a.Attributes.GetAttributes() { + for name, attr := range a.GetAttributes().GetAttributes() { attrReq := tfsdk.ModifyAttributePlanRequest{ AttributePath: req.AttributePath.AtMapKey(key).AtName(name), Config: req.Config, @@ -176,7 +181,7 @@ func AttributeModifyPlan(ctx context.Context, a tfsdk.Attribute, req tfsdk.Modif AttributeModifyPlan(ctx, attr, attrReq, resp) } } - case tfsdk.NestingModeSingle: + case fwschema.NestingModeSingle: o, ok := req.AttributePlan.(types.Object) if !ok { @@ -194,7 +199,7 @@ func AttributeModifyPlan(ctx context.Context, a tfsdk.Attribute, req tfsdk.Modif return } - for name, attr := range a.Attributes.GetAttributes() { + for name, attr := range a.GetAttributes().GetAttributes() { attrReq := tfsdk.ModifyAttributePlanRequest{ AttributePath: req.AttributePath.AtName(name), Config: req.Config, diff --git a/internal/fwserver/attribute_validation.go b/internal/fwserver/attribute_validation.go index 0d3ebb126..229a664ce 100644 --- a/internal/fwserver/attribute_validation.go +++ b/internal/fwserver/attribute_validation.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema/fwxschema" "github.com/hashicorp/terraform-plugin-framework/internal/logging" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -15,10 +17,10 @@ import ( // The extra Attribute parameter is a carry-over of creating the proto6server // package from the tfsdk package and not wanting to export the method. // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/365 -func AttributeValidate(ctx context.Context, a tfsdk.Attribute, req tfsdk.ValidateAttributeRequest, resp *tfsdk.ValidateAttributeResponse) { +func AttributeValidate(ctx context.Context, a fwschema.Attribute, req tfsdk.ValidateAttributeRequest, resp *tfsdk.ValidateAttributeResponse) { ctx = logging.FrameworkWithAttributePath(ctx, req.AttributePath.String()) - if (a.Attributes == nil || len(a.Attributes.GetAttributes()) == 0) && a.Type == nil { + if (a.GetAttributes() == nil || len(a.GetAttributes().GetAttributes()) == 0) && a.GetType() == nil { resp.Diagnostics.AddAttributeError( req.AttributePath, "Invalid Attribute Definition", @@ -28,7 +30,7 @@ func AttributeValidate(ctx context.Context, a tfsdk.Attribute, req tfsdk.Validat return } - if a.Attributes != nil && len(a.Attributes.GetAttributes()) > 0 && a.Type != nil { + if a.GetAttributes() != nil && len(a.GetAttributes().GetAttributes()) > 0 && a.GetType() != nil { resp.Diagnostics.AddAttributeError( req.AttributePath, "Invalid Attribute Definition", @@ -38,7 +40,7 @@ func AttributeValidate(ctx context.Context, a tfsdk.Attribute, req tfsdk.Validat return } - if !a.Required && !a.Optional && !a.Computed { + if !a.IsRequired() && !a.IsOptional() && !a.IsComputed() { resp.Diagnostics.AddAttributeError( req.AttributePath, "Invalid Attribute Definition", @@ -60,7 +62,7 @@ func AttributeValidate(ctx context.Context, a tfsdk.Attribute, req tfsdk.Validat // until Terraform CLI versions 0.12 through the release containing the // checks are considered end-of-life. // Reference: https://github.com/hashicorp/terraform/issues/30669 - if a.Computed && !a.Optional && !attributeConfig.IsNull() { + if a.IsComputed() && !a.IsOptional() && !attributeConfig.IsNull() { resp.Diagnostics.AddAttributeError( req.AttributePath, "Invalid Configuration for Read-Only Attribute", @@ -74,7 +76,7 @@ func AttributeValidate(ctx context.Context, a tfsdk.Attribute, req tfsdk.Validat // until Terraform CLI versions 0.12 through the release containing the // checks are considered end-of-life. // Reference: https://github.com/hashicorp/terraform/issues/30669 - if a.Required && attributeConfig.IsNull() { + if a.IsRequired() && attributeConfig.IsNull() { resp.Diagnostics.AddAttributeError( req.AttributePath, "Missing Configuration for Required Attribute", @@ -85,27 +87,29 @@ func AttributeValidate(ctx context.Context, a tfsdk.Attribute, req tfsdk.Validat req.AttributeConfig = attributeConfig - for _, validator := range a.Validators { - logging.FrameworkDebug( - ctx, - "Calling provider defined AttributeValidator", - map[string]interface{}{ - logging.KeyDescription: validator.Description(ctx), - }, - ) - validator.Validate(ctx, req, resp) - logging.FrameworkDebug( - ctx, - "Called provider defined AttributeValidator", - map[string]interface{}{ - logging.KeyDescription: validator.Description(ctx), - }, - ) + if attributeWithValidators, ok := a.(fwxschema.AttributeWithValidators); ok { + for _, validator := range attributeWithValidators.GetValidators() { + logging.FrameworkDebug( + ctx, + "Calling provider defined AttributeValidator", + map[string]interface{}{ + logging.KeyDescription: validator.Description(ctx), + }, + ) + validator.Validate(ctx, req, resp) + logging.FrameworkDebug( + ctx, + "Called provider defined AttributeValidator", + map[string]interface{}{ + logging.KeyDescription: validator.Description(ctx), + }, + ) + } } AttributeValidateNestedAttributes(ctx, a, req, resp) - if a.DeprecationMessage != "" && attributeConfig != nil { + if a.GetDeprecationMessage() != "" && attributeConfig != nil { tfValue, err := attributeConfig.ToTerraformValue(ctx) if err != nil { resp.Diagnostics.AddAttributeError( @@ -121,7 +125,7 @@ func AttributeValidate(ctx context.Context, a tfsdk.Attribute, req tfsdk.Validat resp.Diagnostics.AddAttributeWarning( req.AttributePath, "Attribute Deprecated", - a.DeprecationMessage, + a.GetDeprecationMessage(), ) } } @@ -133,14 +137,14 @@ func AttributeValidate(ctx context.Context, a tfsdk.Attribute, req tfsdk.Validat // The extra Attribute parameter is a carry-over of creating the proto6server // package from the tfsdk package and not wanting to export the method. // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/365 -func AttributeValidateNestedAttributes(ctx context.Context, a tfsdk.Attribute, req tfsdk.ValidateAttributeRequest, resp *tfsdk.ValidateAttributeResponse) { - if a.Attributes == nil || len(a.Attributes.GetAttributes()) == 0 { +func AttributeValidateNestedAttributes(ctx context.Context, a fwschema.Attribute, req tfsdk.ValidateAttributeRequest, resp *tfsdk.ValidateAttributeResponse) { + if a.GetAttributes() == nil || len(a.GetAttributes().GetAttributes()) == 0 { return } - nm := a.Attributes.GetNestingMode() + nm := a.GetAttributes().GetNestingMode() switch nm { - case tfsdk.NestingModeList: + case fwschema.NestingModeList: l, ok := req.AttributeConfig.(types.List) if !ok { @@ -155,7 +159,7 @@ func AttributeValidateNestedAttributes(ctx context.Context, a tfsdk.Attribute, r } for idx := range l.Elems { - for nestedName, nestedAttr := range a.Attributes.GetAttributes() { + for nestedName, nestedAttr := range a.GetAttributes().GetAttributes() { nestedAttrReq := tfsdk.ValidateAttributeRequest{ AttributePath: req.AttributePath.AtListIndex(idx).AtName(nestedName), AttributePathExpression: req.AttributePathExpression.AtListIndex(idx).AtName(nestedName), @@ -170,7 +174,7 @@ func AttributeValidateNestedAttributes(ctx context.Context, a tfsdk.Attribute, r resp.Diagnostics = nestedAttrResp.Diagnostics } } - case tfsdk.NestingModeSet: + case fwschema.NestingModeSet: s, ok := req.AttributeConfig.(types.Set) if !ok { @@ -185,7 +189,7 @@ func AttributeValidateNestedAttributes(ctx context.Context, a tfsdk.Attribute, r } for _, value := range s.Elems { - for nestedName, nestedAttr := range a.Attributes.GetAttributes() { + for nestedName, nestedAttr := range a.GetAttributes().GetAttributes() { nestedAttrReq := tfsdk.ValidateAttributeRequest{ AttributePath: req.AttributePath.AtSetValue(value).AtName(nestedName), AttributePathExpression: req.AttributePathExpression.AtSetValue(value).AtName(nestedName), @@ -200,7 +204,7 @@ func AttributeValidateNestedAttributes(ctx context.Context, a tfsdk.Attribute, r resp.Diagnostics = nestedAttrResp.Diagnostics } } - case tfsdk.NestingModeMap: + case fwschema.NestingModeMap: m, ok := req.AttributeConfig.(types.Map) if !ok { @@ -215,7 +219,7 @@ func AttributeValidateNestedAttributes(ctx context.Context, a tfsdk.Attribute, r } for key := range m.Elems { - for nestedName, nestedAttr := range a.Attributes.GetAttributes() { + for nestedName, nestedAttr := range a.GetAttributes().GetAttributes() { nestedAttrReq := tfsdk.ValidateAttributeRequest{ AttributePath: req.AttributePath.AtMapKey(key).AtName(nestedName), AttributePathExpression: req.AttributePathExpression.AtMapKey(key).AtName(nestedName), @@ -230,7 +234,7 @@ func AttributeValidateNestedAttributes(ctx context.Context, a tfsdk.Attribute, r resp.Diagnostics = nestedAttrResp.Diagnostics } } - case tfsdk.NestingModeSingle: + case fwschema.NestingModeSingle: o, ok := req.AttributeConfig.(types.Object) if !ok { @@ -245,7 +249,7 @@ func AttributeValidateNestedAttributes(ctx context.Context, a tfsdk.Attribute, r } if !o.Null && !o.Unknown { - for nestedName, nestedAttr := range a.Attributes.GetAttributes() { + for nestedName, nestedAttr := range a.GetAttributes().GetAttributes() { nestedAttrReq := tfsdk.ValidateAttributeRequest{ AttributePath: req.AttributePath.AtName(nestedName), AttributePathExpression: req.AttributePathExpression.AtName(nestedName), diff --git a/internal/fwserver/block_plan_modification.go b/internal/fwserver/block_plan_modification.go index a56935261..7cdfde66f 100644 --- a/internal/fwserver/block_plan_modification.go +++ b/internal/fwserver/block_plan_modification.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema/fwxschema" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -14,7 +16,7 @@ import ( // The extra Block parameter is a carry-over of creating the proto6server // package from the tfsdk package and not wanting to export the method. // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/365 -func BlockModifyPlan(ctx context.Context, b tfsdk.Block, req tfsdk.ModifyAttributePlanRequest, resp *ModifySchemaPlanResponse) { +func BlockModifyPlan(ctx context.Context, b fwschema.Block, req tfsdk.ModifyAttributePlanRequest, resp *ModifySchemaPlanResponse) { attributeConfig, diags := ConfigGetAttributeValue(ctx, req.Config, req.AttributePath) resp.Diagnostics.Append(diags...) @@ -43,21 +45,24 @@ func BlockModifyPlan(ctx context.Context, b tfsdk.Block, req tfsdk.ModifyAttribu req.AttributeState = attributeState var requiresReplace bool - for _, planModifier := range b.PlanModifiers { - modifyResp := &tfsdk.ModifyAttributePlanResponse{ - AttributePlan: req.AttributePlan, - RequiresReplace: requiresReplace, - } - planModifier.Modify(ctx, req, modifyResp) + if blockWithPlanModifiers, ok := b.(fwxschema.BlockWithPlanModifiers); ok { + for _, planModifier := range blockWithPlanModifiers.GetPlanModifiers() { + modifyResp := &tfsdk.ModifyAttributePlanResponse{ + AttributePlan: req.AttributePlan, + RequiresReplace: requiresReplace, + } - req.AttributePlan = modifyResp.AttributePlan - resp.Diagnostics.Append(modifyResp.Diagnostics...) - requiresReplace = modifyResp.RequiresReplace + planModifier.Modify(ctx, req, modifyResp) - // Only on new errors. - if modifyResp.Diagnostics.HasError() { - return + req.AttributePlan = modifyResp.AttributePlan + resp.Diagnostics.Append(modifyResp.Diagnostics...) + requiresReplace = modifyResp.RequiresReplace + + // Only on new errors. + if modifyResp.Diagnostics.HasError() { + return + } } } @@ -72,9 +77,9 @@ func BlockModifyPlan(ctx context.Context, b tfsdk.Block, req tfsdk.ModifyAttribu return } - nm := b.NestingMode + nm := b.GetNestingMode() switch nm { - case tfsdk.BlockNestingModeList: + case fwschema.BlockNestingModeList: l, ok := req.AttributePlan.(types.List) if !ok { @@ -89,7 +94,7 @@ func BlockModifyPlan(ctx context.Context, b tfsdk.Block, req tfsdk.ModifyAttribu } for idx := range l.Elems { - for name, attr := range b.Attributes { + for name, attr := range b.GetAttributes() { attrReq := tfsdk.ModifyAttributePlanRequest{ AttributePath: req.AttributePath.AtListIndex(idx).AtName(name), Config: req.Config, @@ -101,7 +106,7 @@ func BlockModifyPlan(ctx context.Context, b tfsdk.Block, req tfsdk.ModifyAttribu AttributeModifyPlan(ctx, attr, attrReq, resp) } - for name, block := range b.Blocks { + for name, block := range b.GetBlocks() { blockReq := tfsdk.ModifyAttributePlanRequest{ AttributePath: req.AttributePath.AtListIndex(idx).AtName(name), Config: req.Config, @@ -113,7 +118,7 @@ func BlockModifyPlan(ctx context.Context, b tfsdk.Block, req tfsdk.ModifyAttribu BlockModifyPlan(ctx, block, blockReq, resp) } } - case tfsdk.BlockNestingModeSet: + case fwschema.BlockNestingModeSet: s, ok := req.AttributePlan.(types.Set) if !ok { @@ -128,7 +133,7 @@ func BlockModifyPlan(ctx context.Context, b tfsdk.Block, req tfsdk.ModifyAttribu } for _, value := range s.Elems { - for name, attr := range b.Attributes { + for name, attr := range b.GetAttributes() { attrReq := tfsdk.ModifyAttributePlanRequest{ AttributePath: req.AttributePath.AtSetValue(value).AtName(name), Config: req.Config, @@ -140,7 +145,7 @@ func BlockModifyPlan(ctx context.Context, b tfsdk.Block, req tfsdk.ModifyAttribu AttributeModifyPlan(ctx, attr, attrReq, resp) } - for name, block := range b.Blocks { + for name, block := range b.GetBlocks() { blockReq := tfsdk.ModifyAttributePlanRequest{ AttributePath: req.AttributePath.AtSetValue(value).AtName(name), Config: req.Config, diff --git a/internal/fwserver/block_validation.go b/internal/fwserver/block_validation.go index ab16e35b4..c70d9e159 100644 --- a/internal/fwserver/block_validation.go +++ b/internal/fwserver/block_validation.go @@ -6,6 +6,8 @@ import ( "strings" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema/fwxschema" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,7 +19,13 @@ import ( // The extra Block parameter is a carry-over of creating the proto6server // package from the tfsdk package and not wanting to export the method. // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/365 -func BlockValidate(ctx context.Context, b tfsdk.Block, req tfsdk.ValidateAttributeRequest, resp *tfsdk.ValidateAttributeResponse) { +func BlockValidate(ctx context.Context, b fwschema.Block, req tfsdk.ValidateAttributeRequest, resp *tfsdk.ValidateAttributeResponse) { + blockWithValidators, ok := b.(fwxschema.BlockWithValidators) + + if !ok { + return + } + attributeConfig, diags := ConfigGetAttributeValue(ctx, req.Config, req.AttributePath) resp.Diagnostics.Append(diags...) @@ -27,13 +35,13 @@ func BlockValidate(ctx context.Context, b tfsdk.Block, req tfsdk.ValidateAttribu req.AttributeConfig = attributeConfig - for _, validator := range b.Validators { + for _, validator := range blockWithValidators.GetValidators() { validator.Validate(ctx, req, resp) } - nm := b.NestingMode + nm := b.GetNestingMode() switch nm { - case tfsdk.BlockNestingModeList: + case fwschema.BlockNestingModeList: l, ok := req.AttributeConfig.(types.List) if !ok { @@ -48,7 +56,7 @@ func BlockValidate(ctx context.Context, b tfsdk.Block, req tfsdk.ValidateAttribu } for idx := range l.Elems { - for name, attr := range b.Attributes { + for name, attr := range b.GetAttributes() { nestedAttrReq := tfsdk.ValidateAttributeRequest{ AttributePath: req.AttributePath.AtListIndex(idx).AtName(name), AttributePathExpression: req.AttributePathExpression.AtListIndex(idx).AtName(name), @@ -63,7 +71,7 @@ func BlockValidate(ctx context.Context, b tfsdk.Block, req tfsdk.ValidateAttribu resp.Diagnostics = nestedAttrResp.Diagnostics } - for name, block := range b.Blocks { + for name, block := range b.GetBlocks() { nestedAttrReq := tfsdk.ValidateAttributeRequest{ AttributePath: req.AttributePath.AtListIndex(idx).AtName(name), AttributePathExpression: req.AttributePathExpression.AtListIndex(idx).AtName(name), @@ -85,8 +93,8 @@ func BlockValidate(ctx context.Context, b tfsdk.Block, req tfsdk.ValidateAttribu // Terraform 0.15.2 and later implements MaxItems validation during // configuration decoding, so if this framework drops Terraform support // for earlier versions, this validation can be removed. - if b.MaxItems > 0 && int64(len(l.Elems)) > b.MaxItems { - resp.Diagnostics.Append(blockMaxItemsDiagnostic(req.AttributePath, b.MaxItems, len(l.Elems))) + if b.GetMaxItems() > 0 && int64(len(l.Elems)) > b.GetMaxItems() { + resp.Diagnostics.Append(blockMaxItemsDiagnostic(req.AttributePath, b.GetMaxItems(), len(l.Elems))) } // Terraform 0.12 through 0.15.1 implement conservative block MinItems @@ -98,10 +106,10 @@ func BlockValidate(ctx context.Context, b tfsdk.Block, req tfsdk.ValidateAttribu // Terraform 0.15.2 and later implements proper MinItems validation // during configuration decoding, so if this framework drops Terraform // support for earlier versions, this validation can be removed. - if b.MinItems > 0 && int64(len(l.Elems)) < b.MinItems && !l.IsUnknown() { - resp.Diagnostics.Append(blockMinItemsDiagnostic(req.AttributePath, b.MinItems, len(l.Elems))) + if b.GetMinItems() > 0 && int64(len(l.Elems)) < b.GetMinItems() && !l.IsUnknown() { + resp.Diagnostics.Append(blockMinItemsDiagnostic(req.AttributePath, b.GetMinItems(), len(l.Elems))) } - case tfsdk.BlockNestingModeSet: + case fwschema.BlockNestingModeSet: s, ok := req.AttributeConfig.(types.Set) if !ok { @@ -116,7 +124,7 @@ func BlockValidate(ctx context.Context, b tfsdk.Block, req tfsdk.ValidateAttribu } for _, value := range s.Elems { - for name, attr := range b.Attributes { + for name, attr := range b.GetAttributes() { nestedAttrReq := tfsdk.ValidateAttributeRequest{ AttributePath: req.AttributePath.AtSetValue(value).AtName(name), AttributePathExpression: req.AttributePathExpression.AtSetValue(value).AtName(name), @@ -131,7 +139,7 @@ func BlockValidate(ctx context.Context, b tfsdk.Block, req tfsdk.ValidateAttribu resp.Diagnostics = nestedAttrResp.Diagnostics } - for name, block := range b.Blocks { + for name, block := range b.GetBlocks() { nestedAttrReq := tfsdk.ValidateAttributeRequest{ AttributePath: req.AttributePath.AtSetValue(value).AtName(name), AttributePathExpression: req.AttributePathExpression.AtSetValue(value).AtName(name), @@ -153,8 +161,8 @@ func BlockValidate(ctx context.Context, b tfsdk.Block, req tfsdk.ValidateAttribu // Terraform 0.15.2 and later implements MaxItems validation during // configuration decoding, so if this framework drops Terraform support // for earlier versions, this validation can be removed. - if b.MaxItems > 0 && int64(len(s.Elems)) > b.MaxItems { - resp.Diagnostics.Append(blockMaxItemsDiagnostic(req.AttributePath, b.MaxItems, len(s.Elems))) + if b.GetMaxItems() > 0 && int64(len(s.Elems)) > b.GetMaxItems() { + resp.Diagnostics.Append(blockMaxItemsDiagnostic(req.AttributePath, b.GetMaxItems(), len(s.Elems))) } // Terraform 0.12 through 0.15.1 implement conservative block MinItems @@ -166,8 +174,8 @@ func BlockValidate(ctx context.Context, b tfsdk.Block, req tfsdk.ValidateAttribu // Terraform 0.15.2 and later implements proper MinItems validation // during configuration decoding, so if this framework drops Terraform // support for earlier versions, this validation can be removed. - if b.MinItems > 0 && int64(len(s.Elems)) < b.MinItems && !s.IsUnknown() { - resp.Diagnostics.Append(blockMinItemsDiagnostic(req.AttributePath, b.MinItems, len(s.Elems))) + if b.GetMinItems() > 0 && int64(len(s.Elems)) < b.GetMinItems() && !s.IsUnknown() { + resp.Diagnostics.Append(blockMinItemsDiagnostic(req.AttributePath, b.GetMinItems(), len(s.Elems))) } default: err := fmt.Errorf("unknown block validation nesting mode (%T: %v) at path: %s", nm, nm, req.AttributePath) @@ -180,7 +188,7 @@ func BlockValidate(ctx context.Context, b tfsdk.Block, req tfsdk.ValidateAttribu return } - if b.DeprecationMessage != "" && attributeConfig != nil { + if b.GetDeprecationMessage() != "" && attributeConfig != nil { tfValue, err := attributeConfig.ToTerraformValue(ctx) if err != nil { @@ -197,7 +205,7 @@ func BlockValidate(ctx context.Context, b tfsdk.Block, req tfsdk.ValidateAttribu resp.Diagnostics.AddAttributeWarning( req.AttributePath, "Block Deprecated", - b.DeprecationMessage, + b.GetDeprecationMessage(), ) } } diff --git a/internal/fwserver/schema.go b/internal/fwserver/schema.go new file mode 100644 index 000000000..11daf4dbd --- /dev/null +++ b/internal/fwserver/schema.go @@ -0,0 +1,23 @@ +package fwserver + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" +) + +// schema is a temporary function that will return a given fwschema.Schema as +// tfsdk.Schema or panic. This will be removed once tfsdk.Config, tfsdk.Plan, +// and tfsdk.State no longer use tfsdk.Schema directly or are replaced. +// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/366 +func schema(s fwschema.Schema) tfsdk.Schema { + switch s := s.(type) { + case tfsdk.Schema: + return s + case *tfsdk.Schema: + return *s + default: + panic(fmt.Sprintf("unknown fwserver fwschema.Schema type: %T", s)) + } +} diff --git a/internal/fwserver/schema_plan_modification.go b/internal/fwserver/schema_plan_modification.go index 9b85dc7e1..9138f6eca 100644 --- a/internal/fwserver/schema_plan_modification.go +++ b/internal/fwserver/schema_plan_modification.go @@ -4,6 +4,7 @@ import ( "context" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/tfsdk" ) @@ -48,8 +49,8 @@ type ModifySchemaPlanResponse struct { // The extra Schema parameter is a carry-over of creating the proto6server // package from the tfsdk package and not wanting to export the method. // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/365 -func SchemaModifyPlan(ctx context.Context, s tfsdk.Schema, req ModifySchemaPlanRequest, resp *ModifySchemaPlanResponse) { - for name, attribute := range s.Attributes { +func SchemaModifyPlan(ctx context.Context, s fwschema.Schema, req ModifySchemaPlanRequest, resp *ModifySchemaPlanResponse) { + for name, attribute := range s.GetAttributes() { attrReq := tfsdk.ModifyAttributePlanRequest{ AttributePath: path.Root(name), Config: req.Config, @@ -61,7 +62,7 @@ func SchemaModifyPlan(ctx context.Context, s tfsdk.Schema, req ModifySchemaPlanR AttributeModifyPlan(ctx, attribute, attrReq, resp) } - for name, block := range s.Blocks { + for name, block := range s.GetBlocks() { blockReq := tfsdk.ModifyAttributePlanRequest{ AttributePath: path.Root(name), Config: req.Config, diff --git a/internal/fwserver/schema_validation.go b/internal/fwserver/schema_validation.go index adc581687..ce6fbf99a 100644 --- a/internal/fwserver/schema_validation.go +++ b/internal/fwserver/schema_validation.go @@ -4,6 +4,7 @@ import ( "context" "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/tfsdk" ) @@ -32,8 +33,8 @@ type ValidateSchemaResponse struct { // The extra Schema parameter is a carry-over of creating the proto6server // package from the tfsdk package and not wanting to export the method. // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/365 -func SchemaValidate(ctx context.Context, s tfsdk.Schema, req ValidateSchemaRequest, resp *ValidateSchemaResponse) { - for name, attribute := range s.Attributes { +func SchemaValidate(ctx context.Context, s fwschema.Schema, req ValidateSchemaRequest, resp *ValidateSchemaResponse) { + for name, attribute := range s.GetAttributes() { attributeReq := tfsdk.ValidateAttributeRequest{ AttributePath: path.Root(name), @@ -49,7 +50,7 @@ func SchemaValidate(ctx context.Context, s tfsdk.Schema, req ValidateSchemaReque resp.Diagnostics = attributeResp.Diagnostics } - for name, block := range s.Blocks { + for name, block := range s.GetBlocks() { attributeReq := tfsdk.ValidateAttributeRequest{ AttributePath: path.Root(name), AttributePathExpression: path.MatchRoot(name), @@ -64,10 +65,10 @@ func SchemaValidate(ctx context.Context, s tfsdk.Schema, req ValidateSchemaReque resp.Diagnostics = attributeResp.Diagnostics } - if s.DeprecationMessage != "" { + if s.GetDeprecationMessage() != "" { resp.Diagnostics.AddWarning( "Deprecated", - s.DeprecationMessage, + s.GetDeprecationMessage(), ) } } diff --git a/internal/fwserver/server.go b/internal/fwserver/server.go index 03ea0c99f..b9b227db5 100644 --- a/internal/fwserver/server.go +++ b/internal/fwserver/server.go @@ -6,9 +6,9 @@ import ( "sync" "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" ) // Server implements the framework provider server. Protocol specific @@ -20,7 +20,7 @@ type Server struct { // 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. - dataSourceSchemas map[string]*tfsdk.Schema + dataSourceSchemas map[string]fwschema.Schema // dataSourceSchemasDiags is the cached Diagnostics obtained while populating // dataSourceSchemas. This is to ensure any warnings or errors are also @@ -48,7 +48,7 @@ type Server struct { // providerSchema is the cached Provider Schema for RPCs that need to // convert configuration data from the protocol. If not found, it will be // fetched from the Provider.GetSchema() method. - providerSchema *tfsdk.Schema + providerSchema fwschema.Schema // providerSchemaDiags is the cached Diagnostics obtained while populating // providerSchema. This is to ensure any warnings or errors are also @@ -62,7 +62,7 @@ type Server struct { // providerMetaSchema is the cached Provider Meta Schema for RPCs that need // to convert configuration data from the protocol. If not found, it will // be fetched from the Provider.GetMetaSchema() method. - providerMetaSchema *tfsdk.Schema + providerMetaSchema fwschema.Schema // providerMetaSchemaDiags is the cached Diagnostics obtained while populating // providerMetaSchema. This is to ensure any warnings or errors are also @@ -76,7 +76,7 @@ type Server struct { // 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. - resourceSchemas map[string]*tfsdk.Schema + resourceSchemas map[string]fwschema.Schema // resourceSchemasDiags is the cached Diagnostics obtained while populating // resourceSchemas. This is to ensure any warnings or errors are also @@ -104,7 +104,7 @@ type Server struct { // DataSourceSchema returns the Schema associated with the DataSourceType for // the given type name. -func (s *Server) DataSourceSchema(ctx context.Context, typeName string) (*tfsdk.Schema, diag.Diagnostics) { +func (s *Server) DataSourceSchema(ctx context.Context, typeName string) (fwschema.Schema, diag.Diagnostics) { dataSourceSchemas, diags := s.DataSourceSchemas(ctx) dataSourceSchema, ok := dataSourceSchemas[typeName] @@ -124,7 +124,7 @@ func (s *Server) DataSourceSchema(ctx context.Context, typeName string) (*tfsdk. // DataSourceSchemas returns the map of DataSourceType Schemas. The results are // cached on first use. -func (s *Server) DataSourceSchemas(ctx context.Context) (map[string]*tfsdk.Schema, diag.Diagnostics) { +func (s *Server) DataSourceSchemas(ctx context.Context) (map[string]fwschema.Schema, diag.Diagnostics) { logging.FrameworkTrace(ctx, "Checking DataSourceSchemas lock") s.dataSourceSchemasMutex.Lock() defer s.dataSourceSchemasMutex.Unlock() @@ -135,7 +135,7 @@ func (s *Server) DataSourceSchemas(ctx context.Context) (map[string]*tfsdk.Schem dataSourceTypes, diags := s.DataSourceTypes(ctx) - s.dataSourceSchemas = map[string]*tfsdk.Schema{} + s.dataSourceSchemas = map[string]fwschema.Schema{} s.dataSourceSchemasDiags = diags if s.dataSourceSchemasDiags.HasError() { @@ -199,7 +199,7 @@ func (s *Server) DataSourceTypes(ctx context.Context) (map[string]provider.DataS // ProviderSchema returns the Schema associated with the Provider. The Schema // and Diagnostics are cached on first use. -func (s *Server) ProviderSchema(ctx context.Context) (*tfsdk.Schema, diag.Diagnostics) { +func (s *Server) ProviderSchema(ctx context.Context) (fwschema.Schema, diag.Diagnostics) { logging.FrameworkTrace(ctx, "Checking ProviderSchema lock") s.providerSchemaMutex.Lock() defer s.providerSchemaMutex.Unlock() @@ -221,7 +221,7 @@ func (s *Server) ProviderSchema(ctx context.Context) (*tfsdk.Schema, diag.Diagno // ProviderMetaSchema returns the Meta Schema associated with the Provider, if // it implements the ProviderWithMetaSchema interface. The Schema and // Diagnostics are cached on first use. -func (s *Server) ProviderMetaSchema(ctx context.Context) (*tfsdk.Schema, diag.Diagnostics) { +func (s *Server) ProviderMetaSchema(ctx context.Context) (fwschema.Schema, diag.Diagnostics) { providerWithProviderMeta, ok := s.Provider.(provider.ProviderWithMetaSchema) if !ok { @@ -249,7 +249,7 @@ func (s *Server) ProviderMetaSchema(ctx context.Context) (*tfsdk.Schema, diag.Di // ResourceSchema returns the Schema associated with the ResourceType for // the given type name. -func (s *Server) ResourceSchema(ctx context.Context, typeName string) (*tfsdk.Schema, diag.Diagnostics) { +func (s *Server) ResourceSchema(ctx context.Context, typeName string) (fwschema.Schema, diag.Diagnostics) { resourceSchemas, diags := s.ResourceSchemas(ctx) resourceSchema, ok := resourceSchemas[typeName] @@ -269,7 +269,7 @@ func (s *Server) ResourceSchema(ctx context.Context, typeName string) (*tfsdk.Sc // ResourceSchemas returns the map of ResourceType Schemas. The results are // cached on first use. -func (s *Server) ResourceSchemas(ctx context.Context) (map[string]*tfsdk.Schema, diag.Diagnostics) { +func (s *Server) ResourceSchemas(ctx context.Context) (map[string]fwschema.Schema, diag.Diagnostics) { logging.FrameworkTrace(ctx, "Checking ResourceSchemas lock") s.resourceSchemasMutex.Lock() defer s.resourceSchemasMutex.Unlock() @@ -280,7 +280,7 @@ func (s *Server) ResourceSchemas(ctx context.Context) (map[string]*tfsdk.Schema, resourceTypes, diags := s.ResourceTypes(ctx) - s.resourceSchemas = map[string]*tfsdk.Schema{} + s.resourceSchemas = map[string]fwschema.Schema{} s.resourceSchemasDiags = diags if s.resourceSchemasDiags.HasError() { diff --git a/internal/fwserver/server_applyresourcechange.go b/internal/fwserver/server_applyresourcechange.go index 23e8dda3d..975574509 100644 --- a/internal/fwserver/server_applyresourcechange.go +++ b/internal/fwserver/server_applyresourcechange.go @@ -4,6 +4,7 @@ import ( "context" "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" @@ -17,7 +18,7 @@ type ApplyResourceChangeRequest struct { PlannedState *tfsdk.Plan PriorState *tfsdk.State ProviderMeta *tfsdk.Config - ResourceSchema tfsdk.Schema + ResourceSchema fwschema.Schema ResourceType provider.ResourceType } diff --git a/internal/fwserver/server_createresource.go b/internal/fwserver/server_createresource.go index 0eafe4521..443713d2c 100644 --- a/internal/fwserver/server_createresource.go +++ b/internal/fwserver/server_createresource.go @@ -4,6 +4,7 @@ import ( "context" "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" @@ -18,7 +19,7 @@ type CreateResourceRequest struct { PlannedPrivate []byte PlannedState *tfsdk.Plan ProviderMeta *tfsdk.Config - ResourceSchema tfsdk.Schema + ResourceSchema fwschema.Schema ResourceType provider.ResourceType } @@ -52,17 +53,17 @@ func (s *Server) CreateResource(ctx context.Context, req *CreateResourceRequest, createReq := resource.CreateRequest{ Config: tfsdk.Config{ - Schema: req.ResourceSchema, + Schema: schema(req.ResourceSchema), Raw: nullSchemaData, }, Plan: tfsdk.Plan{ - Schema: req.ResourceSchema, + Schema: schema(req.ResourceSchema), Raw: nullSchemaData, }, } createResp := resource.CreateResponse{ State: tfsdk.State{ - Schema: req.ResourceSchema, + Schema: schema(req.ResourceSchema), Raw: nullSchemaData, }, } diff --git a/internal/fwserver/server_deleteresource.go b/internal/fwserver/server_deleteresource.go index 29b92a065..5a894f30f 100644 --- a/internal/fwserver/server_deleteresource.go +++ b/internal/fwserver/server_deleteresource.go @@ -4,6 +4,7 @@ import ( "context" "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" @@ -17,7 +18,7 @@ type DeleteResourceRequest struct { PlannedPrivate []byte PriorState *tfsdk.State ProviderMeta *tfsdk.Config - ResourceSchema tfsdk.Schema + ResourceSchema fwschema.Schema ResourceType provider.ResourceType } @@ -49,13 +50,13 @@ func (s *Server) DeleteResource(ctx context.Context, req *DeleteResourceRequest, deleteReq := resource.DeleteRequest{ State: tfsdk.State{ - Schema: req.ResourceSchema, + Schema: schema(req.ResourceSchema), Raw: tftypes.NewValue(req.ResourceSchema.TerraformType(ctx), nil), }, } deleteResp := resource.DeleteResponse{ State: tfsdk.State{ - Schema: req.ResourceSchema, + Schema: schema(req.ResourceSchema), Raw: tftypes.NewValue(req.ResourceSchema.TerraformType(ctx), nil), }, } diff --git a/internal/fwserver/server_getproviderschema.go b/internal/fwserver/server_getproviderschema.go index bc43ee879..54e9460ff 100644 --- a/internal/fwserver/server_getproviderschema.go +++ b/internal/fwserver/server_getproviderschema.go @@ -4,7 +4,7 @@ import ( "context" "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" ) // GetProviderSchemaRequest is the framework server request for the @@ -15,10 +15,10 @@ type GetProviderSchemaRequest struct{} // GetProviderSchema RPC. type GetProviderSchemaResponse struct { ServerCapabilities *ServerCapabilities - Provider *tfsdk.Schema - ProviderMeta *tfsdk.Schema - ResourceSchemas map[string]*tfsdk.Schema - DataSourceSchemas map[string]*tfsdk.Schema + Provider fwschema.Schema + ProviderMeta fwschema.Schema + ResourceSchemas map[string]fwschema.Schema + DataSourceSchemas map[string]fwschema.Schema Diagnostics diag.Diagnostics } diff --git a/internal/fwserver/server_getproviderschema_test.go b/internal/fwserver/server_getproviderschema_test.go index 15357cc9f..a867c5a84 100644 --- a/internal/fwserver/server_getproviderschema_test.go +++ b/internal/fwserver/server_getproviderschema_test.go @@ -6,6 +6,7 @@ import ( "github.com/google/go-cmp/cmp" "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" @@ -26,9 +27,9 @@ func TestServerGetProviderSchema(t *testing.T) { Provider: &testprovider.Provider{}, }, expectedResponse: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{}, + DataSourceSchemas: map[string]fwschema.Schema{}, Provider: &tfsdk.Schema{}, - ResourceSchemas: map[string]*tfsdk.Schema{}, + ResourceSchemas: map[string]fwschema.Schema{}, ServerCapabilities: &fwserver.ServerCapabilities{ PlanDestroy: true, }, @@ -69,8 +70,8 @@ func TestServerGetProviderSchema(t *testing.T) { }, request: &fwserver.GetProviderSchemaRequest{}, expectedResponse: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source1": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source1": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test1": { Required: true, @@ -78,7 +79,7 @@ func TestServerGetProviderSchema(t *testing.T) { }, }, }, - "test_data_source2": { + "test_data_source2": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test2": { Required: true, @@ -88,7 +89,7 @@ func TestServerGetProviderSchema(t *testing.T) { }, }, Provider: &tfsdk.Schema{}, - ResourceSchemas: map[string]*tfsdk.Schema{}, + ResourceSchemas: map[string]fwschema.Schema{}, ServerCapabilities: &fwserver.ServerCapabilities{ PlanDestroy: true, }, @@ -111,7 +112,7 @@ func TestServerGetProviderSchema(t *testing.T) { }, request: &fwserver.GetProviderSchemaRequest{}, expectedResponse: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{}, + DataSourceSchemas: map[string]fwschema.Schema{}, Provider: &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test": { @@ -120,7 +121,7 @@ func TestServerGetProviderSchema(t *testing.T) { }, }, }, - ResourceSchemas: map[string]*tfsdk.Schema{}, + ResourceSchemas: map[string]fwschema.Schema{}, ServerCapabilities: &fwserver.ServerCapabilities{ PlanDestroy: true, }, @@ -144,7 +145,7 @@ func TestServerGetProviderSchema(t *testing.T) { }, request: &fwserver.GetProviderSchemaRequest{}, expectedResponse: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{}, + DataSourceSchemas: map[string]fwschema.Schema{}, Provider: &tfsdk.Schema{}, ProviderMeta: &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ @@ -154,7 +155,7 @@ func TestServerGetProviderSchema(t *testing.T) { }, }, }, - ResourceSchemas: map[string]*tfsdk.Schema{}, + ResourceSchemas: map[string]fwschema.Schema{}, ServerCapabilities: &fwserver.ServerCapabilities{ PlanDestroy: true, }, @@ -195,10 +196,10 @@ func TestServerGetProviderSchema(t *testing.T) { }, request: &fwserver.GetProviderSchemaRequest{}, expectedResponse: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{}, + DataSourceSchemas: map[string]fwschema.Schema{}, Provider: &tfsdk.Schema{}, - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource1": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource1": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test1": { Required: true, @@ -206,7 +207,7 @@ func TestServerGetProviderSchema(t *testing.T) { }, }, }, - "test_resource2": { + "test_resource2": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test2": { Required: true, diff --git a/internal/fwserver/server_planresourcechange.go b/internal/fwserver/server_planresourcechange.go index 121031802..586fae9b6 100644 --- a/internal/fwserver/server_planresourcechange.go +++ b/internal/fwserver/server_planresourcechange.go @@ -7,6 +7,7 @@ import ( "sort" "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/path" "github.com/hashicorp/terraform-plugin-framework/provider" @@ -23,7 +24,7 @@ type PlanResourceChangeRequest struct { PriorState *tfsdk.State ProposedNewState *tfsdk.Plan ProviderMeta *tfsdk.Config - ResourceSchema tfsdk.Schema + ResourceSchema fwschema.Schema ResourceType provider.ResourceType } @@ -60,21 +61,21 @@ func (s *Server) PlanResourceChange(ctx context.Context, req *PlanResourceChange if req.Config == nil { req.Config = &tfsdk.Config{ Raw: nullTfValue, - Schema: req.ResourceSchema, + Schema: schema(req.ResourceSchema), } } if req.ProposedNewState == nil { req.ProposedNewState = &tfsdk.Plan{ Raw: nullTfValue, - Schema: req.ResourceSchema, + Schema: schema(req.ResourceSchema), } } if req.PriorState == nil { req.PriorState = &tfsdk.State{ Raw: nullTfValue, - Schema: req.ResourceSchema, + Schema: schema(req.ResourceSchema), } } @@ -233,7 +234,7 @@ func (s *Server) PlanResourceChange(ctx context.Context, req *PlanResourceChange } } -func MarkComputedNilsAsUnknown(ctx context.Context, config tftypes.Value, resourceSchema tfsdk.Schema) func(*tftypes.AttributePath, tftypes.Value) (tftypes.Value, error) { +func MarkComputedNilsAsUnknown(ctx context.Context, config tftypes.Value, resourceSchema fwschema.Schema) func(*tftypes.AttributePath, tftypes.Value) (tftypes.Value, error) { return func(path *tftypes.AttributePath, val tftypes.Value) (tftypes.Value, error) { ctx = logging.FrameworkWithAttributePath(ctx, path.String()) @@ -265,7 +266,7 @@ func MarkComputedNilsAsUnknown(ctx context.Context, config tftypes.Value, resour return tftypes.Value{}, fmt.Errorf("couldn't find attribute in resource schema: %w", err) } - if !attribute.Computed { + if !attribute.IsComputed() { logging.FrameworkTrace(ctx, "attribute is not computed in schema, not marking unknown") return val, nil diff --git a/internal/fwserver/server_readdatasource.go b/internal/fwserver/server_readdatasource.go index dd4bda724..1c116d7d1 100644 --- a/internal/fwserver/server_readdatasource.go +++ b/internal/fwserver/server_readdatasource.go @@ -5,6 +5,7 @@ import ( "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/tfsdk" @@ -14,7 +15,7 @@ import ( // ReadDataSource RPC. type ReadDataSourceRequest struct { Config *tfsdk.Config - DataSourceSchema tfsdk.Schema + DataSourceSchema fwschema.Schema DataSourceType provider.DataSourceType ProviderMeta *tfsdk.Config } @@ -45,12 +46,12 @@ func (s *Server) ReadDataSource(ctx context.Context, req *ReadDataSourceRequest, readReq := datasource.ReadRequest{ Config: tfsdk.Config{ - Schema: req.DataSourceSchema, + Schema: schema(req.DataSourceSchema), }, } readResp := datasource.ReadResponse{ State: tfsdk.State{ - Schema: req.DataSourceSchema, + Schema: schema(req.DataSourceSchema), }, } diff --git a/internal/fwserver/server_updateresource.go b/internal/fwserver/server_updateresource.go index b662fa4b0..d8ee7b3ec 100644 --- a/internal/fwserver/server_updateresource.go +++ b/internal/fwserver/server_updateresource.go @@ -4,6 +4,7 @@ import ( "context" "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" @@ -19,7 +20,7 @@ type UpdateResourceRequest struct { PlannedState *tfsdk.Plan PriorState *tfsdk.State ProviderMeta *tfsdk.Config - ResourceSchema tfsdk.Schema + ResourceSchema fwschema.Schema ResourceType provider.ResourceType } @@ -53,21 +54,21 @@ func (s *Server) UpdateResource(ctx context.Context, req *UpdateResourceRequest, updateReq := resource.UpdateRequest{ Config: tfsdk.Config{ - Schema: req.ResourceSchema, + Schema: schema(req.ResourceSchema), Raw: nullSchemaData, }, Plan: tfsdk.Plan{ - Schema: req.ResourceSchema, + Schema: schema(req.ResourceSchema), Raw: nullSchemaData, }, State: tfsdk.State{ - Schema: req.ResourceSchema, + Schema: schema(req.ResourceSchema), Raw: nullSchemaData, }, } updateResp := resource.UpdateResponse{ State: tfsdk.State{ - Schema: req.ResourceSchema, + Schema: schema(req.ResourceSchema), Raw: nullSchemaData, }, } diff --git a/internal/fwserver/server_upgraderesourcestate.go b/internal/fwserver/server_upgraderesourcestate.go index 74696b019..1d9a3a688 100644 --- a/internal/fwserver/server_upgraderesourcestate.go +++ b/internal/fwserver/server_upgraderesourcestate.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-go/tftypes" "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" @@ -21,7 +22,7 @@ type UpgradeResourceStateRequest struct { // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/340 RawState *tfprotov6.RawState - ResourceSchema tfsdk.Schema + ResourceSchema fwschema.Schema ResourceType provider.ResourceType Version int64 } @@ -73,7 +74,7 @@ func (s *Server) UpgradeResourceState(ctx context.Context, req *UpgradeResourceS // // UnmarshalWithOpts allows optionally ignoring instances in which elements being // do not have a corresponding attribute within the schema. - if req.Version == req.ResourceSchema.Version { + if req.Version == req.ResourceSchema.GetVersion() { logging.FrameworkTrace(ctx, "UpgradeResourceState request version matches current Schema version, using framework defined passthrough implementation") resourceSchemaType := req.ResourceSchema.TerraformType(ctx) @@ -92,7 +93,7 @@ func (s *Server) UpgradeResourceState(ctx context.Context, req *UpgradeResourceS } resp.UpgradedState = &tfsdk.State{ - Schema: req.ResourceSchema, + Schema: schema(req.ResourceSchema), Raw: rawStateValue, } @@ -173,7 +174,7 @@ func (s *Server) UpgradeResourceState(ctx context.Context, req *UpgradeResourceS upgradeResourceStateResponse := resource.UpgradeStateResponse{ State: tfsdk.State{ - Schema: req.ResourceSchema, + Schema: schema(req.ResourceSchema), // Raw is intentionally not set. }, } @@ -208,7 +209,7 @@ func (s *Server) UpgradeResourceState(ctx context.Context, req *UpgradeResourceS } resp.UpgradedState = &tfsdk.State{ - Schema: req.ResourceSchema, + Schema: schema(req.ResourceSchema), Raw: upgradedStateValue, } diff --git a/internal/toproto5/block.go b/internal/toproto5/block.go index d6c4fac1d..573799f49 100644 --- a/internal/toproto5/block.go +++ b/internal/toproto5/block.go @@ -4,7 +4,7 @@ import ( "context" "sort" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-go/tfprotov5" "github.com/hashicorp/terraform-plugin-go/tftypes" ) @@ -12,37 +12,37 @@ import ( // Block returns the *tfprotov5.SchemaNestedBlock equivalent of a Block. // Errors will be tftypes.AttributePathErrors based on `path`. `name` is the // name of the attribute. -func Block(ctx context.Context, name string, path *tftypes.AttributePath, b tfsdk.Block) (*tfprotov5.SchemaNestedBlock, error) { +func Block(ctx context.Context, name string, path *tftypes.AttributePath, b fwschema.Block) (*tfprotov5.SchemaNestedBlock, error) { schemaNestedBlock := &tfprotov5.SchemaNestedBlock{ Block: &tfprotov5.SchemaBlock{ - Deprecated: b.DeprecationMessage != "", + Deprecated: b.GetDeprecationMessage() != "", }, - MinItems: b.MinItems, - MaxItems: b.MaxItems, + MinItems: b.GetMinItems(), + MaxItems: b.GetMaxItems(), TypeName: name, } - if b.Description != "" { - schemaNestedBlock.Block.Description = b.Description + if b.GetDescription() != "" { + schemaNestedBlock.Block.Description = b.GetDescription() schemaNestedBlock.Block.DescriptionKind = tfprotov5.StringKindPlain } - if b.MarkdownDescription != "" { - schemaNestedBlock.Block.Description = b.MarkdownDescription + if b.GetMarkdownDescription() != "" { + schemaNestedBlock.Block.Description = b.GetMarkdownDescription() schemaNestedBlock.Block.DescriptionKind = tfprotov5.StringKindMarkdown } - nm := b.NestingMode + nm := b.GetNestingMode() switch nm { - case tfsdk.BlockNestingModeList: + case fwschema.BlockNestingModeList: schemaNestedBlock.Nesting = tfprotov5.SchemaNestedBlockNestingModeList - case tfsdk.BlockNestingModeSet: + case fwschema.BlockNestingModeSet: schemaNestedBlock.Nesting = tfprotov5.SchemaNestedBlockNestingModeSet default: return nil, path.NewErrorf("unrecognized nesting mode %v", nm) } - for attrName, attr := range b.Attributes { + for attrName, attr := range b.GetAttributes() { attrPath := path.WithAttributeName(attrName) attrProto5, err := SchemaAttribute(ctx, attrName, attrPath, attr) @@ -53,7 +53,7 @@ func Block(ctx context.Context, name string, path *tftypes.AttributePath, b tfsd schemaNestedBlock.Block.Attributes = append(schemaNestedBlock.Block.Attributes, attrProto5) } - for blockName, block := range b.Blocks { + for blockName, block := range b.GetBlocks() { blockPath := path.WithAttributeName(blockName) blockProto5, err := Block(ctx, blockName, blockPath, block) diff --git a/internal/toproto5/block_test.go b/internal/toproto5/block_test.go index d2f71cb8c..877576a95 100644 --- a/internal/toproto5/block_test.go +++ b/internal/toproto5/block_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/toproto5" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,7 +18,7 @@ func TestBlock(t *testing.T) { type testCase struct { name string - block tfsdk.Block + block fwschema.Block path *tftypes.AttributePath expected *tfprotov5.SchemaNestedBlock expectedErr string diff --git a/internal/toproto5/getproviderschema_test.go b/internal/toproto5/getproviderschema_test.go index 83ebc8d01..0f1d26da8 100644 --- a/internal/toproto5/getproviderschema_test.go +++ b/internal/toproto5/getproviderschema_test.go @@ -6,6 +6,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/toproto5" "github.com/hashicorp/terraform-plugin-framework/tfsdk" @@ -31,8 +32,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-multiple-data-sources": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source_1": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source_1": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -40,7 +41,7 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, }, }, - "test_data_source_2": { + "test_data_source_2": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -80,8 +81,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-computed": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -110,8 +111,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-deprecated": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { DeprecationMessage: "deprecated", @@ -142,8 +143,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-optional": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Optional: true, @@ -172,8 +173,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-optional-computed": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -204,8 +205,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-required": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -234,8 +235,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-sensitive": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -266,8 +267,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-bool": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -296,8 +297,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-float64": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -326,8 +327,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-int64": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -356,8 +357,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-list-list-string": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -394,8 +395,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-list-nested-attributes": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Attributes: tfsdk.ListNestedAttributes(map[string]tfsdk.Attribute{ @@ -426,8 +427,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-list-object": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -468,8 +469,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-list-string": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -502,8 +503,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-map-nested-attributes": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Attributes: tfsdk.MapNestedAttributes(map[string]tfsdk.Attribute{ @@ -534,8 +535,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-map-string": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -568,8 +569,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-number": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -598,8 +599,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-object": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -636,8 +637,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-set-nested-attributes": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Attributes: tfsdk.SetNestedAttributes(map[string]tfsdk.Attribute{ @@ -668,8 +669,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-set-object": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -710,8 +711,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-set-set-string": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -748,8 +749,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-set-string": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -782,8 +783,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-single-nested-attributes": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Attributes: tfsdk.SingleNestedAttributes(map[string]tfsdk.Attribute{ @@ -814,8 +815,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-string": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -844,8 +845,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-block-list": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Blocks: map[string]tfsdk.Block{ "test_block": { Attributes: map[string]tfsdk.Attribute{ @@ -887,8 +888,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-block-set": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Blocks: map[string]tfsdk.Block{ "test_block": { Attributes: map[string]tfsdk.Attribute{ @@ -930,8 +931,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-version": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Version: 123, }, }, @@ -2520,8 +2521,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-multiple-resources": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource_1": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource_1": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -2529,7 +2530,7 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, }, }, - "test_resource_2": { + "test_resource_2": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -2569,8 +2570,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-computed": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -2599,8 +2600,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-deprecated": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { DeprecationMessage: "deprecated", @@ -2631,8 +2632,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-optional": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Optional: true, @@ -2661,8 +2662,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-optional-computed": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -2693,8 +2694,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-required": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -2723,8 +2724,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-sensitive": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -2755,8 +2756,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-bool": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -2785,8 +2786,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-float64": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -2815,8 +2816,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-int64": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -2845,8 +2846,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-list-list-string": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -2883,8 +2884,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-list-nested-attributes": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Attributes: tfsdk.ListNestedAttributes(map[string]tfsdk.Attribute{ @@ -2915,8 +2916,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-list-object": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -2957,8 +2958,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-list-string": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -2991,8 +2992,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-map-nested-attributes": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Attributes: tfsdk.MapNestedAttributes(map[string]tfsdk.Attribute{ @@ -3023,8 +3024,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-map-string": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -3057,8 +3058,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-number": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -3087,8 +3088,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-object": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -3125,8 +3126,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-set-nested-attributes": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Attributes: tfsdk.SetNestedAttributes(map[string]tfsdk.Attribute{ @@ -3157,8 +3158,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-set-object": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -3199,8 +3200,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-set-set-string": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -3237,8 +3238,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-set-string": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -3271,8 +3272,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-single-nested-attributes": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Attributes: tfsdk.SingleNestedAttributes(map[string]tfsdk.Attribute{ @@ -3303,8 +3304,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-string": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -3333,8 +3334,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-block-list": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Blocks: map[string]tfsdk.Block{ "test_block": { Attributes: map[string]tfsdk.Attribute{ @@ -3376,8 +3377,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-block-set": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Blocks: map[string]tfsdk.Block{ "test_block": { Attributes: map[string]tfsdk.Attribute{ @@ -3419,8 +3420,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-version": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Version: 123, }, }, diff --git a/internal/toproto5/schema.go b/internal/toproto5/schema.go index f115d2588..1ca1530f6 100644 --- a/internal/toproto5/schema.go +++ b/internal/toproto5/schema.go @@ -4,25 +4,25 @@ import ( "context" "sort" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-go/tfprotov5" "github.com/hashicorp/terraform-plugin-go/tftypes" ) // Schema returns the *tfprotov5.Schema equivalent of a Schema. -func Schema(ctx context.Context, s *tfsdk.Schema) (*tfprotov5.Schema, error) { +func Schema(ctx context.Context, s fwschema.Schema) (*tfprotov5.Schema, error) { if s == nil { return nil, nil } result := &tfprotov5.Schema{ - Version: s.Version, + Version: s.GetVersion(), } var attrs []*tfprotov5.SchemaAttribute var blocks []*tfprotov5.SchemaNestedBlock - for name, attr := range s.Attributes { + for name, attr := range s.GetAttributes() { a, err := SchemaAttribute(ctx, name, tftypes.NewAttributePath().WithAttributeName(name), attr) if err != nil { @@ -32,7 +32,7 @@ func Schema(ctx context.Context, s *tfsdk.Schema) (*tfprotov5.Schema, error) { attrs = append(attrs, a) } - for name, block := range s.Blocks { + for name, block := range s.GetBlocks() { proto5, err := Block(ctx, name, tftypes.NewAttributePath().WithAttributeName(name), block) if err != nil { @@ -71,16 +71,16 @@ func Schema(ctx context.Context, s *tfsdk.Schema) (*tfprotov5.Schema, error) { // so let's not set it. Attributes: attrs, BlockTypes: blocks, - Deprecated: s.DeprecationMessage != "", + Deprecated: s.GetDeprecationMessage() != "", } - if s.Description != "" { - result.Block.Description = s.Description + if s.GetDescription() != "" { + result.Block.Description = s.GetDescription() result.Block.DescriptionKind = tfprotov5.StringKindPlain } - if s.MarkdownDescription != "" { - result.Block.Description = s.MarkdownDescription + if s.GetMarkdownDescription() != "" { + result.Block.Description = s.GetMarkdownDescription() result.Block.DescriptionKind = tfprotov5.StringKindMarkdown } diff --git a/internal/toproto5/schema_attribute.go b/internal/toproto5/schema_attribute.go index 55538a203..563e8f912 100644 --- a/internal/toproto5/schema_attribute.go +++ b/internal/toproto5/schema_attribute.go @@ -3,7 +3,7 @@ package toproto5 import ( "context" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-go/tfprotov5" "github.com/hashicorp/terraform-plugin-go/tftypes" ) @@ -11,39 +11,39 @@ import ( // SchemaAttribute returns the *tfprotov5.SchemaAttribute equivalent of an // Attribute. Errors will be tftypes.AttributePathErrors based on `path`. // `name` is the name of the attribute. -func SchemaAttribute(ctx context.Context, name string, path *tftypes.AttributePath, a tfsdk.Attribute) (*tfprotov5.SchemaAttribute, error) { - if a.Attributes != nil && len(a.Attributes.GetAttributes()) > 0 { +func SchemaAttribute(ctx context.Context, name string, path *tftypes.AttributePath, a fwschema.Attribute) (*tfprotov5.SchemaAttribute, error) { + if a.GetAttributes() != nil && len(a.GetAttributes().GetAttributes()) > 0 { return nil, path.NewErrorf("protocol version 5 cannot have Attributes set") } - if a.Type == nil { + if a.GetType() == nil { return nil, path.NewErrorf("must have Type set") } - if !a.Required && !a.Optional && !a.Computed { + if !a.IsRequired() && !a.IsOptional() && !a.IsComputed() { return nil, path.NewErrorf("must have Required, Optional, or Computed set") } schemaAttribute := &tfprotov5.SchemaAttribute{ Name: name, - Required: a.Required, - Optional: a.Optional, - Computed: a.Computed, - Sensitive: a.Sensitive, - Type: a.Type.TerraformType(ctx), + Required: a.IsRequired(), + Optional: a.IsOptional(), + Computed: a.IsComputed(), + Sensitive: a.IsSensitive(), + Type: a.GetType().TerraformType(ctx), } - if a.DeprecationMessage != "" { + if a.GetDeprecationMessage() != "" { schemaAttribute.Deprecated = true } - if a.Description != "" { - schemaAttribute.Description = a.Description + if a.GetDescription() != "" { + schemaAttribute.Description = a.GetDescription() schemaAttribute.DescriptionKind = tfprotov5.StringKindPlain } - if a.MarkdownDescription != "" { - schemaAttribute.Description = a.MarkdownDescription + if a.GetMarkdownDescription() != "" { + schemaAttribute.Description = a.GetMarkdownDescription() schemaAttribute.DescriptionKind = tfprotov5.StringKindMarkdown } diff --git a/internal/toproto5/schema_attribute_test.go b/internal/toproto5/schema_attribute_test.go index 444fdfb7f..d9512007b 100644 --- a/internal/toproto5/schema_attribute_test.go +++ b/internal/toproto5/schema_attribute_test.go @@ -6,6 +6,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/toproto5" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -18,7 +19,7 @@ func TestSchemaAttribute(t *testing.T) { type testCase struct { name string - attr tfsdk.Attribute + attr fwschema.Attribute path *tftypes.AttributePath expected *tfprotov5.SchemaAttribute expectedErr string diff --git a/internal/toproto5/schema_test.go b/internal/toproto5/schema_test.go index c18c94735..68fdb6a2e 100644 --- a/internal/toproto5/schema_test.go +++ b/internal/toproto5/schema_test.go @@ -6,6 +6,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/toproto5" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,7 +18,7 @@ func TestSchema(t *testing.T) { t.Parallel() type testCase struct { - input *tfsdk.Schema + input fwschema.Schema expected *tfprotov5.Schema expectedErr string } diff --git a/internal/toproto6/block.go b/internal/toproto6/block.go index 7a27ea005..fb6f60334 100644 --- a/internal/toproto6/block.go +++ b/internal/toproto6/block.go @@ -4,7 +4,7 @@ import ( "context" "sort" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-go/tfprotov6" "github.com/hashicorp/terraform-plugin-go/tftypes" ) @@ -12,37 +12,37 @@ import ( // Block returns the *tfprotov6.SchemaNestedBlock equivalent of a Block. // Errors will be tftypes.AttributePathErrors based on `path`. `name` is the // name of the attribute. -func Block(ctx context.Context, name string, path *tftypes.AttributePath, b tfsdk.Block) (*tfprotov6.SchemaNestedBlock, error) { +func Block(ctx context.Context, name string, path *tftypes.AttributePath, b fwschema.Block) (*tfprotov6.SchemaNestedBlock, error) { schemaNestedBlock := &tfprotov6.SchemaNestedBlock{ Block: &tfprotov6.SchemaBlock{ - Deprecated: b.DeprecationMessage != "", + Deprecated: b.GetDeprecationMessage() != "", }, - MinItems: b.MinItems, - MaxItems: b.MaxItems, + MinItems: b.GetMinItems(), + MaxItems: b.GetMaxItems(), TypeName: name, } - if b.Description != "" { - schemaNestedBlock.Block.Description = b.Description + if b.GetDescription() != "" { + schemaNestedBlock.Block.Description = b.GetDescription() schemaNestedBlock.Block.DescriptionKind = tfprotov6.StringKindPlain } - if b.MarkdownDescription != "" { - schemaNestedBlock.Block.Description = b.MarkdownDescription + if b.GetMarkdownDescription() != "" { + schemaNestedBlock.Block.Description = b.GetMarkdownDescription() schemaNestedBlock.Block.DescriptionKind = tfprotov6.StringKindMarkdown } - nm := b.NestingMode + nm := b.GetNestingMode() switch nm { - case tfsdk.BlockNestingModeList: + case fwschema.BlockNestingModeList: schemaNestedBlock.Nesting = tfprotov6.SchemaNestedBlockNestingModeList - case tfsdk.BlockNestingModeSet: + case fwschema.BlockNestingModeSet: schemaNestedBlock.Nesting = tfprotov6.SchemaNestedBlockNestingModeSet default: return nil, path.NewErrorf("unrecognized nesting mode %v", nm) } - for attrName, attr := range b.Attributes { + for attrName, attr := range b.GetAttributes() { attrPath := path.WithAttributeName(attrName) attrProto6, err := SchemaAttribute(ctx, attrName, attrPath, attr) @@ -53,7 +53,7 @@ func Block(ctx context.Context, name string, path *tftypes.AttributePath, b tfsd schemaNestedBlock.Block.Attributes = append(schemaNestedBlock.Block.Attributes, attrProto6) } - for blockName, block := range b.Blocks { + for blockName, block := range b.GetBlocks() { blockPath := path.WithAttributeName(blockName) blockProto6, err := Block(ctx, blockName, blockPath, block) diff --git a/internal/toproto6/block_test.go b/internal/toproto6/block_test.go index 94adebdc6..5b46d22a2 100644 --- a/internal/toproto6/block_test.go +++ b/internal/toproto6/block_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/toproto6" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,7 +18,7 @@ func TestBlock(t *testing.T) { type testCase struct { name string - block tfsdk.Block + block fwschema.Block path *tftypes.AttributePath expected *tfprotov6.SchemaNestedBlock expectedErr string diff --git a/internal/toproto6/getproviderschema_test.go b/internal/toproto6/getproviderschema_test.go index eaf65ea99..7e2bc9a08 100644 --- a/internal/toproto6/getproviderschema_test.go +++ b/internal/toproto6/getproviderschema_test.go @@ -6,6 +6,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/fwserver" "github.com/hashicorp/terraform-plugin-framework/internal/toproto6" "github.com/hashicorp/terraform-plugin-framework/tfsdk" @@ -31,8 +32,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-multiple-data-sources": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source_1": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source_1": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -40,7 +41,7 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, }, }, - "test_data_source_2": { + "test_data_source_2": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -80,8 +81,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-computed": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -110,8 +111,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-deprecated": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { DeprecationMessage: "deprecated", @@ -142,8 +143,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-optional": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Optional: true, @@ -172,8 +173,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-optional-computed": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -204,8 +205,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-required": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -234,8 +235,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-sensitive": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -266,8 +267,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-bool": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -296,8 +297,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-float64": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -326,8 +327,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-int64": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -356,8 +357,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-list-list-string": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -394,8 +395,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-list-nested-attributes": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Attributes: tfsdk.ListNestedAttributes(map[string]tfsdk.Attribute{ @@ -438,8 +439,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-list-object": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -480,8 +481,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-list-string": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -514,8 +515,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-map-nested-attributes": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Attributes: tfsdk.MapNestedAttributes(map[string]tfsdk.Attribute{ @@ -558,8 +559,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-map-string": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -592,8 +593,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-number": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -622,8 +623,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-object": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -660,8 +661,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-set-nested-attributes": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Attributes: tfsdk.SetNestedAttributes(map[string]tfsdk.Attribute{ @@ -704,8 +705,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-set-object": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -746,8 +747,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-set-set-string": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -784,8 +785,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-set-string": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -818,8 +819,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-single-nested-attributes": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Attributes: tfsdk.SingleNestedAttributes(map[string]tfsdk.Attribute{ @@ -862,8 +863,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-attribute-type-string": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -892,8 +893,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-block-list": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Blocks: map[string]tfsdk.Block{ "test_block": { Attributes: map[string]tfsdk.Attribute{ @@ -935,8 +936,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-block-set": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Blocks: map[string]tfsdk.Block{ "test_block": { Attributes: map[string]tfsdk.Attribute{ @@ -978,8 +979,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "data-source-version": { input: &fwserver.GetProviderSchemaResponse{ - DataSourceSchemas: map[string]*tfsdk.Schema{ - "test_data_source": { + DataSourceSchemas: map[string]fwschema.Schema{ + "test_data_source": &tfsdk.Schema{ Version: 123, }, }, @@ -2672,8 +2673,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-multiple-resources": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource_1": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource_1": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -2681,7 +2682,7 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, }, }, - "test_resource_2": { + "test_resource_2": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -2721,8 +2722,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-computed": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -2751,8 +2752,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-deprecated": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { DeprecationMessage: "deprecated", @@ -2783,8 +2784,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-optional": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Optional: true, @@ -2813,8 +2814,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-optional-computed": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -2845,8 +2846,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-required": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -2875,8 +2876,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-sensitive": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Computed: true, @@ -2907,8 +2908,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-bool": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -2937,8 +2938,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-float64": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -2967,8 +2968,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-int64": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -2997,8 +2998,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-list-list-string": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -3035,8 +3036,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-list-nested-attributes": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Attributes: tfsdk.ListNestedAttributes(map[string]tfsdk.Attribute{ @@ -3079,8 +3080,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-list-object": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -3121,8 +3122,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-list-string": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -3155,8 +3156,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-map-nested-attributes": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Attributes: tfsdk.MapNestedAttributes(map[string]tfsdk.Attribute{ @@ -3199,8 +3200,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-map-string": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -3233,8 +3234,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-number": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -3263,8 +3264,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-object": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -3301,8 +3302,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-set-nested-attributes": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Attributes: tfsdk.SetNestedAttributes(map[string]tfsdk.Attribute{ @@ -3345,8 +3346,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-set-object": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -3387,8 +3388,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-set-set-string": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -3425,8 +3426,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-set-string": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -3459,8 +3460,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-single-nested-attributes": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Attributes: tfsdk.SingleNestedAttributes(map[string]tfsdk.Attribute{ @@ -3503,8 +3504,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-attribute-type-string": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Attributes: map[string]tfsdk.Attribute{ "test_attribute": { Required: true, @@ -3533,8 +3534,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-block-list": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Blocks: map[string]tfsdk.Block{ "test_block": { Attributes: map[string]tfsdk.Attribute{ @@ -3576,8 +3577,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-block-set": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Blocks: map[string]tfsdk.Block{ "test_block": { Attributes: map[string]tfsdk.Attribute{ @@ -3619,8 +3620,8 @@ func TestGetProviderSchemaResponse(t *testing.T) { }, "resource-version": { input: &fwserver.GetProviderSchemaResponse{ - ResourceSchemas: map[string]*tfsdk.Schema{ - "test_resource": { + ResourceSchemas: map[string]fwschema.Schema{ + "test_resource": &tfsdk.Schema{ Version: 123, }, }, diff --git a/internal/toproto6/schema.go b/internal/toproto6/schema.go index 19026ee19..da1ce1e73 100644 --- a/internal/toproto6/schema.go +++ b/internal/toproto6/schema.go @@ -4,25 +4,25 @@ import ( "context" "sort" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-go/tfprotov6" "github.com/hashicorp/terraform-plugin-go/tftypes" ) // Schema returns the *tfprotov6.Schema equivalent of a Schema. -func Schema(ctx context.Context, s *tfsdk.Schema) (*tfprotov6.Schema, error) { +func Schema(ctx context.Context, s fwschema.Schema) (*tfprotov6.Schema, error) { if s == nil { return nil, nil } result := &tfprotov6.Schema{ - Version: s.Version, + Version: s.GetVersion(), } var attrs []*tfprotov6.SchemaAttribute var blocks []*tfprotov6.SchemaNestedBlock - for name, attr := range s.Attributes { + for name, attr := range s.GetAttributes() { a, err := SchemaAttribute(ctx, name, tftypes.NewAttributePath().WithAttributeName(name), attr) if err != nil { @@ -32,7 +32,7 @@ func Schema(ctx context.Context, s *tfsdk.Schema) (*tfprotov6.Schema, error) { attrs = append(attrs, a) } - for name, block := range s.Blocks { + for name, block := range s.GetBlocks() { proto6, err := Block(ctx, name, tftypes.NewAttributePath().WithAttributeName(name), block) if err != nil { @@ -71,16 +71,16 @@ func Schema(ctx context.Context, s *tfsdk.Schema) (*tfprotov6.Schema, error) { // so let's not set it. Attributes: attrs, BlockTypes: blocks, - Deprecated: s.DeprecationMessage != "", + Deprecated: s.GetDeprecationMessage() != "", } - if s.Description != "" { - result.Block.Description = s.Description + if s.GetDescription() != "" { + result.Block.Description = s.GetDescription() result.Block.DescriptionKind = tfprotov6.StringKindPlain } - if s.MarkdownDescription != "" { - result.Block.Description = s.MarkdownDescription + if s.GetMarkdownDescription() != "" { + result.Block.Description = s.GetMarkdownDescription() result.Block.DescriptionKind = tfprotov6.StringKindMarkdown } diff --git a/internal/toproto6/schema_attribute.go b/internal/toproto6/schema_attribute.go index 4bc891db9..4f22174e5 100644 --- a/internal/toproto6/schema_attribute.go +++ b/internal/toproto6/schema_attribute.go @@ -4,7 +4,7 @@ import ( "context" "sort" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-go/tfprotov6" "github.com/hashicorp/terraform-plugin-go/tftypes" ) @@ -12,63 +12,63 @@ import ( // SchemaAttribute returns the *tfprotov6.SchemaAttribute equivalent of an // Attribute. Errors will be tftypes.AttributePathErrors based on `path`. // `name` is the name of the attribute. -func SchemaAttribute(ctx context.Context, name string, path *tftypes.AttributePath, a tfsdk.Attribute) (*tfprotov6.SchemaAttribute, error) { - if a.Attributes != nil && len(a.Attributes.GetAttributes()) > 0 && a.Type != nil { +func SchemaAttribute(ctx context.Context, name string, path *tftypes.AttributePath, a fwschema.Attribute) (*tfprotov6.SchemaAttribute, error) { + if a.GetAttributes() != nil && len(a.GetAttributes().GetAttributes()) > 0 && a.GetType() != nil { return nil, path.NewErrorf("cannot have both Attributes and Type set") } - if (a.Attributes == nil || len(a.Attributes.GetAttributes()) == 0) && a.Type == nil { + if (a.GetAttributes() == nil || len(a.GetAttributes().GetAttributes()) == 0) && a.GetType() == nil { return nil, path.NewErrorf("must have Attributes or Type set") } - if !a.Required && !a.Optional && !a.Computed { + if !a.IsRequired() && !a.IsOptional() && !a.IsComputed() { return nil, path.NewErrorf("must have Required, Optional, or Computed set") } schemaAttribute := &tfprotov6.SchemaAttribute{ Name: name, - Required: a.Required, - Optional: a.Optional, - Computed: a.Computed, - Sensitive: a.Sensitive, + Required: a.IsRequired(), + Optional: a.IsOptional(), + Computed: a.IsComputed(), + Sensitive: a.IsSensitive(), } - if a.DeprecationMessage != "" { + if a.GetDeprecationMessage() != "" { schemaAttribute.Deprecated = true } - if a.Description != "" { - schemaAttribute.Description = a.Description + if a.GetDescription() != "" { + schemaAttribute.Description = a.GetDescription() schemaAttribute.DescriptionKind = tfprotov6.StringKindPlain } - if a.MarkdownDescription != "" { - schemaAttribute.Description = a.MarkdownDescription + if a.GetMarkdownDescription() != "" { + schemaAttribute.Description = a.GetMarkdownDescription() schemaAttribute.DescriptionKind = tfprotov6.StringKindMarkdown } - if a.Type != nil { - schemaAttribute.Type = a.Type.TerraformType(ctx) + if a.GetType() != nil { + schemaAttribute.Type = a.GetType().TerraformType(ctx) return schemaAttribute, nil } object := &tfprotov6.SchemaObject{} - nm := a.Attributes.GetNestingMode() + nm := a.GetAttributes().GetNestingMode() switch nm { - case tfsdk.NestingModeSingle: + case fwschema.NestingModeSingle: object.Nesting = tfprotov6.SchemaObjectNestingModeSingle - case tfsdk.NestingModeList: + case fwschema.NestingModeList: object.Nesting = tfprotov6.SchemaObjectNestingModeList - case tfsdk.NestingModeSet: + case fwschema.NestingModeSet: object.Nesting = tfprotov6.SchemaObjectNestingModeSet - case tfsdk.NestingModeMap: + case fwschema.NestingModeMap: object.Nesting = tfprotov6.SchemaObjectNestingModeMap default: return nil, path.NewErrorf("unrecognized nesting mode %v", nm) } - for nestedName, nestedA := range a.Attributes.GetAttributes() { + for nestedName, nestedA := range a.GetAttributes().GetAttributes() { nestedSchemaAttribute, err := SchemaAttribute(ctx, nestedName, path.WithAttributeName(nestedName), nestedA) if err != nil { diff --git a/internal/toproto6/schema_attribute_test.go b/internal/toproto6/schema_attribute_test.go index 95d46ef61..78c6947b7 100644 --- a/internal/toproto6/schema_attribute_test.go +++ b/internal/toproto6/schema_attribute_test.go @@ -6,6 +6,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/toproto6" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -18,7 +19,7 @@ func TestSchemaAttribute(t *testing.T) { type testCase struct { name string - attr tfsdk.Attribute + attr fwschema.Attribute path *tftypes.AttributePath expected *tfprotov6.SchemaAttribute expectedErr string diff --git a/internal/toproto6/schema_test.go b/internal/toproto6/schema_test.go index 1e7075670..39d57d98e 100644 --- a/internal/toproto6/schema_test.go +++ b/internal/toproto6/schema_test.go @@ -6,6 +6,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/internal/toproto6" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,7 +18,7 @@ func TestSchema(t *testing.T) { t.Parallel() type testCase struct { - input *tfsdk.Schema + input fwschema.Schema expected *tfprotov6.Schema expectedErr string } diff --git a/resource/plan_modifiers.go b/resource/plan_modifiers.go index 23f9f1677..f61f45b7a 100644 --- a/resource/plan_modifiers.go +++ b/resource/plan_modifiers.go @@ -112,7 +112,7 @@ func (r requiresReplaceModifier) Modify(ctx context.Context, req tfsdk.ModifyAtt return } - if req.AttributeConfig.IsNull() && attrSchema.Computed { + if req.AttributeConfig.IsNull() && attrSchema.IsComputed() { // if the config is null and the attribute is computed, this // could be an out of band change, don't require replace return @@ -257,7 +257,7 @@ func (r requiresReplaceIfModifier) Modify(ctx context.Context, req tfsdk.ModifyA return } - if req.AttributeConfig.IsNull() && attrSchema.Computed { + if req.AttributeConfig.IsNull() && attrSchema.IsComputed() { // if the config is null and the attribute is computed, this // could be an out of band change, don't require replace return diff --git a/tfsdk/attribute.go b/tfsdk/attribute.go index 362d84085..45ba1049a 100644 --- a/tfsdk/attribute.go +++ b/tfsdk/attribute.go @@ -5,9 +5,16 @@ import ( "errors" "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-go/tftypes" ) +// Attribute must satify the fwschema.Attribute interface. It must also satisfy +// fwxschema.AttributeWithPlanModifiers and fwxschema.AttributeWithValidators +// interfaces, however we cannot check that here or it would introduce an +// import cycle. +var _ fwschema.Attribute = Attribute{} + // Attribute defines the constraints and behaviors of a single value field in a // schema. Attributes are the fields that show up in Terraform state files and // can be used in configuration files. @@ -23,7 +30,7 @@ type Attribute struct { // type. // // If Attributes is set, Type cannot be. - Attributes NestedAttributes + Attributes fwschema.NestedAttributes // Description is used in various tooling, like the language server, to // give practitioners more information about what this attribute is, @@ -149,54 +156,104 @@ func (a Attribute) ApplyTerraform5AttributePathStep(step tftypes.AttributePathSt } // Equal returns true if `a` and `o` should be considered Equal. -func (a Attribute) Equal(o Attribute) bool { - if a.Type == nil && o.Type != nil { +func (a Attribute) Equal(o fwschema.Attribute) bool { + if _, ok := o.(Attribute); !ok { + return false + } + if a.GetType() == nil && o.GetType() != nil { return false - } else if a.Type != nil && o.Type == nil { + } else if a.GetType() != nil && o.GetType() == nil { return false - } else if a.Type != nil && o.Type != nil && !a.Type.Equal(o.Type) { + } else if a.GetType() != nil && o.GetType() != nil && !a.GetType().Equal(o.GetType()) { return false } - if a.Attributes == nil && o.Attributes != nil { + if a.GetAttributes() == nil && o.GetAttributes() != nil { return false - } else if a.Attributes != nil && o.Attributes == nil { + } else if a.GetAttributes() != nil && o.GetAttributes() == nil { return false - } else if a.Attributes != nil && o.Attributes != nil && !a.Attributes.Equal(o.Attributes) { + } else if a.GetAttributes() != nil && o.GetAttributes() != nil && !a.GetAttributes().Equal(o.GetAttributes()) { return false } - if a.Description != o.Description { + if a.GetDescription() != o.GetDescription() { return false } - if a.MarkdownDescription != o.MarkdownDescription { + if a.GetMarkdownDescription() != o.GetMarkdownDescription() { return false } - if a.Required != o.Required { + if a.IsRequired() != o.IsRequired() { return false } - if a.Optional != o.Optional { + if a.IsOptional() != o.IsOptional() { return false } - if a.Computed != o.Computed { + if a.IsComputed() != o.IsComputed() { return false } - if a.Sensitive != o.Sensitive { + if a.IsSensitive() != o.IsSensitive() { return false } - if a.DeprecationMessage != o.DeprecationMessage { + if a.GetDeprecationMessage() != o.GetDeprecationMessage() { return false } return true } -// attributeType returns an attr.Type corresponding to the attribute. -func (a Attribute) attributeType() attr.Type { - if a.Attributes != nil { - return a.Attributes.AttributeType() - } +// GetAttributes satisfies the fwschema.Attribute interface. +func (a Attribute) GetAttributes() fwschema.NestedAttributes { + return a.Attributes +} + +// GetDeprecationMessage satisfies the fwschema.Attribute interface. +func (a Attribute) GetDeprecationMessage() string { + return a.DeprecationMessage +} + +// GetDescription satisfies the fwschema.Attribute interface. +func (a Attribute) GetDescription() string { + return a.Description +} + +// GetMarkdownDescription satisfies the fwschema.Attribute interface. +func (a Attribute) GetMarkdownDescription() string { + return a.MarkdownDescription +} +// GetPlanModifiers satisfies the fwxschema.AttributeWithPlanModifiers +// interface. +func (a Attribute) GetPlanModifiers() AttributePlanModifiers { + return a.PlanModifiers +} + +// GetValidators satisfies the fwxschema.AttributeWithValidators interface. +func (a Attribute) GetValidators() []AttributeValidator { + return a.Validators +} + +// GetType satisfies the fwschema.Attribute interface. +func (a Attribute) GetType() attr.Type { return a.Type } +// IsComputed satisfies the fwschema.Attribute interface. +func (a Attribute) IsComputed() bool { + return a.Computed +} + +// IsOptional satisfies the fwschema.Attribute interface. +func (a Attribute) IsOptional() bool { + return a.Optional +} + +// IsRequired satisfies the fwschema.Attribute interface. +func (a Attribute) IsRequired() bool { + return a.Required +} + +// IsSensitive satisfies the fwschema.Attribute interface. +func (a Attribute) IsSensitive() bool { + return a.Sensitive +} + // terraformType returns an tftypes.Type corresponding to the attribute. func (a Attribute) terraformType(ctx context.Context) tftypes.Type { if a.Attributes != nil { diff --git a/tfsdk/attribute_test.go b/tfsdk/attribute_test.go index f963b93e4..3281ac8c7 100644 --- a/tfsdk/attribute_test.go +++ b/tfsdk/attribute_test.go @@ -10,83 +10,13 @@ import ( "github.com/hashicorp/terraform-plugin-go/tftypes" ) -func TestAttributeAttributeType(t *testing.T) { +func TestAttributeGetType(t *testing.T) { t.Parallel() testCases := map[string]struct { attribute Attribute expected attr.Type }{ - "Attributes-ListNestedAttributes": { - attribute: Attribute{ - Attributes: ListNestedAttributes(map[string]Attribute{ - "test_nested_attribute": { - Required: true, - Type: types.StringType, - }, - }), - Required: true, - }, - expected: types.ListType{ - ElemType: types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "test_nested_attribute": types.StringType, - }, - }, - }, - }, - "Attributes-MapNestedAttributes": { - attribute: Attribute{ - Attributes: MapNestedAttributes(map[string]Attribute{ - "test_nested_attribute": { - Required: true, - Type: types.StringType, - }, - }), - Required: true, - }, - expected: types.MapType{ - ElemType: types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "test_nested_attribute": types.StringType, - }, - }, - }, - }, - "Attributes-SetNestedAttributes": { - attribute: Attribute{ - Attributes: SetNestedAttributes(map[string]Attribute{ - "test_nested_attribute": { - Required: true, - Type: types.StringType, - }, - }), - Required: true, - }, - expected: types.SetType{ - ElemType: types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "test_nested_attribute": types.StringType, - }, - }, - }, - }, - "Attributes-SingleNestedAttributes": { - attribute: Attribute{ - Attributes: SingleNestedAttributes(map[string]Attribute{ - "test_nested_attribute": { - Required: true, - Type: types.StringType, - }, - }), - Required: true, - }, - expected: types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "test_nested_attribute": types.StringType, - }, - }, - }, "Type-BoolType": { attribute: Attribute{ Required: true, @@ -178,7 +108,7 @@ func TestAttributeAttributeType(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := testCase.attribute.attributeType() + got := testCase.attribute.GetType() if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/tfsdk/block.go b/tfsdk/block.go index eca0e447e..f1c128ead 100644 --- a/tfsdk/block.go +++ b/tfsdk/block.go @@ -6,12 +6,19 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-go/tftypes" ) var _ tftypes.AttributePathStepper = Block{} +// Block must satify the fwschema.Block interface. It must also satisfy +// fwxschema.BlockWithPlanModifiers and fwxschema.BlockWithValidators +// interfaces, however we cannot check that here or it would introduce an +// import cycle. +var _ fwschema.Block = Block{} + // Block defines the constraints and behaviors of a single structural field in a // schema. // @@ -69,7 +76,7 @@ type Block struct { // NestingMode indicates the block kind. This field must be set or a // runtime error will be raised by the framework when fetching the schema. - NestingMode BlockNestingMode + NestingMode fwschema.BlockNestingMode // PlanModifiers defines a sequence of modifiers for this block at // plan time. Block-level plan modifications occur before any @@ -100,7 +107,7 @@ func (b Block) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) return nil, fmt.Errorf("can't apply %T to block NestingModeList", step) } - return nestedBlock{Block: b}, nil + return fwschema.NestedBlock{Block: b}, nil case BlockNestingModeSet: _, ok := step.(tftypes.ElementKeyValue) @@ -108,53 +115,104 @@ func (b Block) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) return nil, fmt.Errorf("can't apply %T to block NestingModeSet", step) } - return nestedBlock{Block: b}, nil + return fwschema.NestedBlock{Block: b}, nil default: return nil, fmt.Errorf("unsupported block nesting mode: %v", b.NestingMode) } } // Equal returns true if `b` and `o` should be considered Equal. -func (b Block) Equal(o Block) bool { - if !cmp.Equal(b.Attributes, o.Attributes) { +func (b Block) Equal(o fwschema.Block) bool { + if !cmp.Equal(b.GetAttributes(), o.GetAttributes()) { return false } - if !cmp.Equal(b.Blocks, o.Blocks) { + if !cmp.Equal(b.GetBlocks(), o.GetBlocks()) { return false } - if b.DeprecationMessage != o.DeprecationMessage { + if b.GetDeprecationMessage() != o.GetDeprecationMessage() { return false } - if b.Description != o.Description { + if b.GetDescription() != o.GetDescription() { return false } - if b.MarkdownDescription != o.MarkdownDescription { + if b.GetMarkdownDescription() != o.GetMarkdownDescription() { return false } - if b.MaxItems != o.MaxItems { + if b.GetMaxItems() != o.GetMaxItems() { return false } - if b.MinItems != o.MinItems { + if b.GetMinItems() != o.GetMinItems() { return false } - if b.NestingMode != o.NestingMode { + if b.GetNestingMode() != o.GetNestingMode() { return false } return true } +// GetAttributes satisfies the fwschema.Block interface. +func (b Block) GetAttributes() map[string]fwschema.Attribute { + return schemaAttributes(b.Attributes) +} + +// GetBlocks satisfies the fwschema.Block interface. +func (b Block) GetBlocks() map[string]fwschema.Block { + return schemaBlocks(b.Blocks) +} + +// GetDeprecationMessage satisfies the fwschema.Block interface. +func (b Block) GetDeprecationMessage() string { + return b.DeprecationMessage +} + +// GetDescription satisfies the fwschema.Block interface. +func (b Block) GetDescription() string { + return b.Description +} + +// GetMarkdownDescription satisfies the fwschema.Block interface. +func (b Block) GetMarkdownDescription() string { + return b.MarkdownDescription +} + +// GetMaxItems satisfies the fwschema.Block interface. +func (b Block) GetMaxItems() int64 { + return b.MaxItems +} + +// GetMinItems satisfies the fwschema.Block interface. +func (b Block) GetMinItems() int64 { + return b.MinItems +} + +// GetNestingMode satisfies the fwschema.Block interface. +func (b Block) GetNestingMode() fwschema.BlockNestingMode { + return b.NestingMode +} + +// GetPlanModifiers satisfies the fwxschema.BlockWithPlanModifiers +// interface. +func (b Block) GetPlanModifiers() AttributePlanModifiers { + return b.PlanModifiers +} + +// GetValidators satisfies the fwxschema.BlockWithValidators interface. +func (b Block) GetValidators() []AttributeValidator { + return b.Validators +} + // attributeType returns an attr.Type corresponding to the block. -func (b Block) attributeType() attr.Type { +func (b Block) Type() attr.Type { attrType := types.ObjectType{ AttrTypes: map[string]attr.Type{}, } for attrName, attr := range b.Attributes { - attrType.AttrTypes[attrName] = attr.attributeType() + attrType.AttrTypes[attrName] = attr.GetType() } for blockName, block := range b.Blocks { - attrType.AttrTypes[blockName] = block.attributeType() + attrType.AttrTypes[blockName] = block.Type() } switch b.NestingMode { @@ -173,31 +231,5 @@ func (b Block) attributeType() attr.Type { // terraformType returns an tftypes.Type corresponding to the block. func (b Block) terraformType(ctx context.Context) tftypes.Type { - return b.attributeType().TerraformType(ctx) -} - -type nestedBlock struct { - Block -} - -// ApplyTerraform5AttributePathStep allows Blocks to be walked using -// tftypes.Walk and tftypes.Transform. -func (b nestedBlock) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (interface{}, error) { - a, ok := step.(tftypes.AttributeName) - - if !ok { - return nil, fmt.Errorf("can't apply %T to block", step) - } - - attrName := string(a) - - if attr, ok := b.Block.Attributes[attrName]; ok { - return attr, nil - } - - if block, ok := b.Block.Blocks[attrName]; ok { - return block, nil - } - - return nil, fmt.Errorf("no attribute %q on Attributes or Blocks", a) + return b.Type().TerraformType(ctx) } diff --git a/tfsdk/block_nested_mode.go b/tfsdk/block_nested_mode.go index a2b034f50..24cd5eea8 100644 --- a/tfsdk/block_nested_mode.go +++ b/tfsdk/block_nested_mode.go @@ -1,26 +1,10 @@ package tfsdk -// BlockNestingMode is an enum type of the ways attributes and blocks can be -// nested in a block. They can be a list or a set. -// -// While the protocol and theoretically Terraform itself support map, single, -// and group nesting modes, this framework intentionally only supports list -// and set blocks as those other modes were not typically implemented or -// tested since the older Terraform Plugin SDK did not support them. -type BlockNestingMode uint8 +import ( + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" +) const ( - // BlockNestingModeUnknown is an invalid nesting mode, used to catch when a - // nesting mode is expected and not set. - BlockNestingModeUnknown BlockNestingMode = 0 - - // BlockNestingModeList is for attributes that represent a list of objects, - // with multiple instances of those attributes nested inside a list - // under another attribute. - BlockNestingModeList BlockNestingMode = 1 - - // BlockNestingModeSet is for attributes that represent a set of objects, - // with multiple, unique instances of those attributes nested inside a - // set under another attribute. - BlockNestingModeSet BlockNestingMode = 2 + BlockNestingModeList = fwschema.BlockNestingModeList + BlockNestingModeSet = fwschema.BlockNestingModeSet ) diff --git a/tfsdk/block_test.go b/tfsdk/block_test.go index ed9786230..44092e2dc 100644 --- a/tfsdk/block_test.go +++ b/tfsdk/block_test.go @@ -97,7 +97,7 @@ func TestBlockAttributeType(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - got := testCase.block.attributeType() + got := testCase.block.Type() if diff := cmp.Diff(got, testCase.expected); diff != "" { t.Errorf("unexpected difference: %s", diff) diff --git a/tfsdk/nested_attributes.go b/tfsdk/nested_attributes.go index 9259d3128..48bf792f2 100644 --- a/tfsdk/nested_attributes.go +++ b/tfsdk/nested_attributes.go @@ -1,301 +1,42 @@ package tfsdk import ( - "fmt" - - "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" ) -// NestingMode is an enum type of the ways nested attributes can be nested in -// an attribute. They can be a list, a set, a map (with string -// keys), or they can be nested directly, like an object. -type NestingMode uint8 - -const ( - // NestingModeUnknown is an invalid nesting mode, used to catch when a - // nesting mode is expected and not set. - NestingModeUnknown NestingMode = 0 - - // NestingModeSingle is for attributes that represent a struct or - // object, a single instance of those attributes directly nested under - // another attribute. - NestingModeSingle NestingMode = 1 - - // NestingModeList is for attributes that represent a list of objects, - // with multiple instances of those attributes nested inside a list - // under another attribute. - NestingModeList NestingMode = 2 - - // NestingModeSet is for attributes that represent a set of objects, - // with multiple, unique instances of those attributes nested inside a - // set under another attribute. - NestingModeSet NestingMode = 3 - - // NestingModeMap is for attributes that represent a map of objects, - // with multiple instances of those attributes, each associated with a - // unique string key, nested inside a map under another attribute. - NestingModeMap NestingMode = 4 -) - -// NestedAttributes surfaces a group of attributes to nest beneath another -// attribute, and how that nesting should behave. Nesting can have the -// following modes: -// -// * SingleNestedAttributes are nested attributes that represent a struct or -// object; there should only be one instance of them nested beneath that -// specific attribute. -// -// * ListNestedAttributes are nested attributes that represent a list of -// structs or objects; there can be multiple instances of them beneath that -// specific attribute. -// -// * SetNestedAttributes are nested attributes that represent a set of structs -// or objects; there can be multiple instances of them beneath that specific -// attribute. Unlike ListNestedAttributes, these nested attributes must have -// unique values. -// -// * MapNestedAttributes are nested attributes that represent a string-indexed -// map of structs or objects; there can be multiple instances of them beneath -// that specific attribute. Unlike ListNestedAttributes, these nested -// attributes must be associated with a unique key. Unlike SetNestedAttributes, -// the key must be explicitly set by the user. -type NestedAttributes interface { - tftypes.AttributePathStepper - AttributeType() attr.Type - GetNestingMode() NestingMode - GetAttributes() map[string]Attribute - Equal(NestedAttributes) bool - unimplementable() -} - -type nestedAttributes map[string]Attribute - -func (n nestedAttributes) GetAttributes() map[string]Attribute { - return n -} - -func (n nestedAttributes) unimplementable() {} - -func (n nestedAttributes) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (interface{}, error) { - a, ok := step.(tftypes.AttributeName) - if !ok { - return nil, fmt.Errorf("can't apply %T to Attributes", step) - } - res, ok := n[string(a)] - if !ok { - return nil, fmt.Errorf("no attribute %q on Attributes", a) - } - return res, nil -} - -// AttributeType returns an attr.Type corresponding to the nested attributes. -func (n nestedAttributes) AttributeType() attr.Type { - attrTypes := map[string]attr.Type{} - for name, attr := range n.GetAttributes() { - if attr.Type != nil { - attrTypes[name] = attr.Type - } - if attr.Attributes != nil { - attrTypes[name] = attr.Attributes.AttributeType() - } - } - return types.ObjectType{ - AttrTypes: attrTypes, - } -} - -// SingleNestedAttributes nests `attributes` under another attribute, only -// allowing one instance of that group of attributes to appear in the -// configuration. -func SingleNestedAttributes(attributes map[string]Attribute) NestedAttributes { - return singleNestedAttributes{ - attributes, - } -} - -type singleNestedAttributes struct { - nestedAttributes -} - -func (s singleNestedAttributes) GetNestingMode() NestingMode { - return NestingModeSingle -} - -func (s singleNestedAttributes) Equal(o NestedAttributes) bool { - other, ok := o.(singleNestedAttributes) - if !ok { - return false - } - if len(other.nestedAttributes) != len(s.nestedAttributes) { - return false - } - for k, v := range s.nestedAttributes { - otherV, ok := other.nestedAttributes[k] - if !ok { - return false - } - if !v.Equal(otherV) { - return false - } - } - return true -} - // ListNestedAttributes nests `attributes` under another attribute, allowing // multiple instances of that group of attributes to appear in the // configuration. -func ListNestedAttributes(attributes map[string]Attribute) NestedAttributes { - return listNestedAttributes{ - nestedAttributes: nestedAttributes(attributes), - } -} - -type listNestedAttributes struct { - nestedAttributes -} - -func (l listNestedAttributes) GetNestingMode() NestingMode { - return NestingModeList -} - -// AttributeType returns an attr.Type corresponding to the nested attributes. -func (l listNestedAttributes) AttributeType() attr.Type { - return types.ListType{ - ElemType: l.nestedAttributes.AttributeType(), +func ListNestedAttributes(attributes map[string]Attribute) fwschema.NestedAttributes { + return fwschema.ListNestedAttributes{ + UnderlyingAttributes: schemaAttributes(attributes), } } -func (l listNestedAttributes) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (interface{}, error) { - _, ok := step.(tftypes.ElementKeyInt) - if !ok { - return nil, fmt.Errorf("can't apply %T to ListNestedAttributes", step) - } - return l.nestedAttributes, nil -} - -func (l listNestedAttributes) Equal(o NestedAttributes) bool { - other, ok := o.(listNestedAttributes) - if !ok { - return false - } - if len(other.nestedAttributes) != len(l.nestedAttributes) { - return false - } - for k, v := range l.nestedAttributes { - otherV, ok := other.nestedAttributes[k] - if !ok { - return false - } - if !v.Equal(otherV) { - return false - } - } - return true -} - -// SetNestedAttributes nests `attributes` under another attribute, allowing -// multiple instances of that group of attributes to appear in the -// configuration, while requiring each group of values be unique. -func SetNestedAttributes(attributes map[string]Attribute) NestedAttributes { - return setNestedAttributes{ - nestedAttributes: nestedAttributes(attributes), - } -} - -type setNestedAttributes struct { - nestedAttributes -} - -func (s setNestedAttributes) GetNestingMode() NestingMode { - return NestingModeSet -} - -// AttributeType returns an attr.Type corresponding to the nested attributes. -func (s setNestedAttributes) AttributeType() attr.Type { - return types.SetType{ - ElemType: s.nestedAttributes.AttributeType(), - } -} - -func (s setNestedAttributes) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (interface{}, error) { - _, ok := step.(tftypes.ElementKeyValue) - if !ok { - return nil, fmt.Errorf("can't use %T on sets", step) - } - return s.nestedAttributes, nil -} - -func (s setNestedAttributes) Equal(o NestedAttributes) bool { - other, ok := o.(setNestedAttributes) - if !ok { - return false - } - if len(other.nestedAttributes) != len(s.nestedAttributes) { - return false - } - for k, v := range s.nestedAttributes { - otherV, ok := other.nestedAttributes[k] - if !ok { - return false - } - if !v.Equal(otherV) { - return false - } - } - return true -} - // MapNestedAttributes nests `attributes` under another attribute, allowing // multiple instances of that group of attributes to appear in the // configuration. Each group will need to be associated with a unique string by // the user. -func MapNestedAttributes(attributes map[string]Attribute) NestedAttributes { - return mapNestedAttributes{ - nestedAttributes: nestedAttributes(attributes), - } -} - -type mapNestedAttributes struct { - nestedAttributes -} - -func (m mapNestedAttributes) GetNestingMode() NestingMode { - return NestingModeMap -} - -// AttributeType returns an attr.Type corresponding to the nested attributes. -func (m mapNestedAttributes) AttributeType() attr.Type { - return types.MapType{ - ElemType: m.nestedAttributes.AttributeType(), +func MapNestedAttributes(attributes map[string]Attribute) fwschema.NestedAttributes { + return fwschema.MapNestedAttributes{ + UnderlyingAttributes: schemaAttributes(attributes), } } -func (m mapNestedAttributes) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) (interface{}, error) { - _, ok := step.(tftypes.ElementKeyString) - if !ok { - return nil, fmt.Errorf("can't use %T on maps", step) +// SetNestedAttributes nests `attributes` under another attribute, allowing +// multiple instances of that group of attributes to appear in the +// configuration, while requiring each group of values be unique. +func SetNestedAttributes(attributes map[string]Attribute) fwschema.NestedAttributes { + return fwschema.SetNestedAttributes{ + UnderlyingAttributes: schemaAttributes(attributes), } - return m.nestedAttributes, nil } -func (m mapNestedAttributes) Equal(o NestedAttributes) bool { - other, ok := o.(mapNestedAttributes) - if !ok { - return false - } - if len(other.nestedAttributes) != len(m.nestedAttributes) { - return false - } - for k, v := range m.nestedAttributes { - otherV, ok := other.nestedAttributes[k] - if !ok { - return false - } - if !v.Equal(otherV) { - return false - } +// SingleNestedAttributes nests `attributes` under another attribute, only +// allowing one instance of that group of attributes to appear in the +// configuration. +func SingleNestedAttributes(attributes map[string]Attribute) fwschema.NestedAttributes { + return fwschema.SingleNestedAttributes{ + UnderlyingAttributes: schemaAttributes(attributes), } - return true } diff --git a/tfsdk/schema.go b/tfsdk/schema.go index ddccf72a6..6dc89e6c6 100644 --- a/tfsdk/schema.go +++ b/tfsdk/schema.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/internal/fwschema" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-go/tftypes" ) @@ -22,6 +23,9 @@ var ( ErrPathIsBlock = errors.New("path leads to block, not an attribute") ) +// Schema must satify the fwschema.Schema interface. +var _ fwschema.Schema = Schema{} + // Schema is used to define the shape of practitioner-provider information, // like resources, data sources, and providers. Think of it as a type // definition, but for Terraform. @@ -98,10 +102,15 @@ func (s Schema) ApplyTerraform5AttributePathStep(step tftypes.AttributePathStep) func (s Schema) AttributeType() attr.Type { attrTypes := map[string]attr.Type{} for name, attr := range s.Attributes { - attrTypes[name] = attr.attributeType() + if attr.GetAttributes() != nil { + attrTypes[name] = attr.GetAttributes().AttributeType() + continue + } + + attrTypes[name] = attr.GetType() } for name, block := range s.Blocks { - attrTypes[name] = block.attributeType() + attrTypes[name] = block.Type() } return types.ObjectType{AttrTypes: attrTypes} } @@ -116,14 +125,18 @@ func (s Schema) AttributeTypeAtPath(path *tftypes.AttributePath) (attr.Type, err switch typ := rawType.(type) { case attr.Type: return typ, nil - case nestedAttributes: + case fwschema.UnderlyingAttributes: return typ.AttributeType(), nil - case nestedBlock: - return typ.Block.attributeType(), nil + case fwschema.NestedBlock: + return typ.Block.Type(), nil case Attribute: - return typ.attributeType(), nil + if typ.GetAttributes() != nil { + return typ.GetAttributes().AttributeType(), nil + } + + return typ.GetType(), nil case Block: - return typ.attributeType(), nil + return typ.Type(), nil case Schema: return typ.AttributeType(), nil default: @@ -131,6 +144,36 @@ func (s Schema) AttributeTypeAtPath(path *tftypes.AttributePath) (attr.Type, err } } +// GetAttributes satisfies the fwschema.Schema interface. +func (s Schema) GetAttributes() map[string]fwschema.Attribute { + return schemaAttributes(s.Attributes) +} + +// GetBlocks satisfies the fwschema.Schema interface. +func (s Schema) GetBlocks() map[string]fwschema.Block { + return schemaBlocks(s.Blocks) +} + +// GetDeprecationMessage satisfies the fwschema.Schema interface. +func (s Schema) GetDeprecationMessage() string { + return s.DeprecationMessage +} + +// GetDescription satisfies the fwschema.Schema interface. +func (s Schema) GetDescription() string { + return s.Description +} + +// GetMarkdownDescription satisfies the fwschema.Schema interface. +func (s Schema) GetMarkdownDescription() string { + return s.MarkdownDescription +} + +// GetVersion satisfies the fwschema.Schema interface. +func (s Schema) GetVersion() int64 { + return s.Version +} + // TerraformType returns a tftypes.Type that can represent the schema. func (s Schema) TerraformType(ctx context.Context) tftypes.Type { attrTypes := map[string]tftypes.Type{} @@ -146,7 +189,7 @@ func (s Schema) TerraformType(ctx context.Context) tftypes.Type { // AttributeAtPath returns the Attribute at the passed path. If the path points // to an element or attribute of a complex type, rather than to an Attribute, // it will return an ErrPathInsideAtomicAttribute error. -func (s Schema) AttributeAtPath(path *tftypes.AttributePath) (Attribute, error) { +func (s Schema) AttributeAtPath(path *tftypes.AttributePath) (fwschema.Attribute, error) { res, remaining, err := tftypes.WalkAttributePath(s, path) if err != nil { return Attribute{}, fmt.Errorf("%v still remains in the path: %w", remaining, err) @@ -155,11 +198,11 @@ func (s Schema) AttributeAtPath(path *tftypes.AttributePath) (Attribute, error) switch r := res.(type) { case attr.Type: return Attribute{}, ErrPathInsideAtomicAttribute - case nestedAttributes: + case fwschema.UnderlyingAttributes: return Attribute{}, ErrPathInsideAtomicAttribute - case nestedBlock: + case fwschema.NestedBlock: return Attribute{}, ErrPathInsideAtomicAttribute - case Attribute: + case fwschema.Attribute: return r, nil case Block: return Attribute{}, ErrPathIsBlock @@ -167,3 +210,25 @@ func (s Schema) AttributeAtPath(path *tftypes.AttributePath) (Attribute, error) return Attribute{}, fmt.Errorf("got unexpected type %T", res) } } + +// schemaAttributes is a tfsdk to fwschema type conversion function. +func schemaAttributes(attributes map[string]Attribute) map[string]fwschema.Attribute { + result := make(map[string]fwschema.Attribute, len(attributes)) + + for name, attribute := range attributes { + result[name] = attribute + } + + return result +} + +// schemaBlocks is a tfsdk to fwschema type conversion function. +func schemaBlocks(blocks map[string]Block) map[string]fwschema.Block { + result := make(map[string]fwschema.Block, len(blocks)) + + for name, block := range blocks { + result[name] = block + } + + return result +}