From 1c8c7ac062eae7c355515dd52350bcb0d50262b1 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Fri, 16 Dec 2022 09:11:37 -0500 Subject: [PATCH 1/5] deps: bump terraform-plugin-framework to 1.0.0 --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 9f6516aaf8c8..f7c33bb5eeca 100644 --- a/go.mod +++ b/go.mod @@ -44,12 +44,12 @@ require ( github.com/hashicorp/go-uuid v1.0.3 github.com/hashicorp/go-version v1.6.0 github.com/hashicorp/hcl/v2 v2.15.0 - github.com/hashicorp/terraform-plugin-framework v0.17.0 - github.com/hashicorp/terraform-plugin-framework-timeouts v0.2.0 - github.com/hashicorp/terraform-plugin-framework-validators v0.7.0 + github.com/hashicorp/terraform-plugin-framework v1.0.1 + github.com/hashicorp/terraform-plugin-framework-timeouts v0.3.0 + github.com/hashicorp/terraform-plugin-framework-validators v0.9.0 github.com/hashicorp/terraform-plugin-go v0.14.2 github.com/hashicorp/terraform-plugin-log v0.7.0 - github.com/hashicorp/terraform-plugin-mux v0.7.0 + github.com/hashicorp/terraform-plugin-mux v0.8.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.1 github.com/mattbaird/jsonpatch v0.0.0-20200820163806-098863c1fc24 github.com/mitchellh/cli v1.1.5 diff --git a/go.sum b/go.sum index 3860d662f2b9..38ce92b275d4 100644 --- a/go.sum +++ b/go.sum @@ -214,18 +214,18 @@ github.com/hashicorp/terraform-exec v0.17.3 h1:MX14Kvnka/oWGmIkyuyvL6POx25ZmKrjl github.com/hashicorp/terraform-exec v0.17.3/go.mod h1:+NELG0EqQekJzhvikkeQsOAZpsw0cv/03rbeQJqscAI= github.com/hashicorp/terraform-json v0.14.0 h1:sh9iZ1Y8IFJLx+xQiKHGud6/TSUCM0N8e17dKDpqV7s= github.com/hashicorp/terraform-json v0.14.0/go.mod h1:5A9HIWPkk4e5aeeXIBbkcOvaZbIYnAIkEyqP2pNSckM= -github.com/hashicorp/terraform-plugin-framework v0.17.0 h1:0KUOY/oe1GPLFqaXnKDnd1rhCrnUtt8pV9wGEwNUFlU= -github.com/hashicorp/terraform-plugin-framework v0.17.0/go.mod h1:FV97t2BZOARkL7NNlsc/N25c84MyeSSz72uPp7Vq1lg= -github.com/hashicorp/terraform-plugin-framework-timeouts v0.2.0 h1:qo+9WNxAg9UlD0NHoOhi6GJOjQKN6b+JLZJOZ5Nqr8g= -github.com/hashicorp/terraform-plugin-framework-timeouts v0.2.0/go.mod h1:jIV0yknjnzb3Al+DRMtr25BPlQq8LLoy+36bYQduIg8= -github.com/hashicorp/terraform-plugin-framework-validators v0.7.0 h1:tIYOMNmEMQIc6mwun8nX3e5U3TkgZg1TpXRlBEBQHwY= -github.com/hashicorp/terraform-plugin-framework-validators v0.7.0/go.mod h1:e1RKREyEVdd3FK8Jfgz8L/ThQgcJKLb4ZJxNzsuIH0A= +github.com/hashicorp/terraform-plugin-framework v1.0.1 h1:apX2jtaEKa15+do6H2izBJdl1dEH2w5BPVkDJ3Q3mKA= +github.com/hashicorp/terraform-plugin-framework v1.0.1/go.mod h1:FV97t2BZOARkL7NNlsc/N25c84MyeSSz72uPp7Vq1lg= +github.com/hashicorp/terraform-plugin-framework-timeouts v0.3.0 h1:+JyyLOcqpnq3aELxmWWxMH5g55ml8NsyLWmYkcSR2fk= +github.com/hashicorp/terraform-plugin-framework-timeouts v0.3.0/go.mod h1:ZvvDe5yPEf3lAv9IP6cqwobqFeXsPMJtPXMX3ZYxahQ= +github.com/hashicorp/terraform-plugin-framework-validators v0.9.0 h1:LYz4bXh3t7bTEydXOmPDPupRRnA480B/9+jV8yZvxBA= +github.com/hashicorp/terraform-plugin-framework-validators v0.9.0/go.mod h1:+BVERsnfdlhYR2YkXMBtPnmn9UsL19U3qUtSZ+Y/5MY= github.com/hashicorp/terraform-plugin-go v0.14.2 h1:rhsVEOGCnY04msNymSvbUsXfRLKh9znXZmHlf5e8mhE= github.com/hashicorp/terraform-plugin-go v0.14.2/go.mod h1:Q12UjumPNGiFsZffxOsA40Tlz1WVXt2Evh865Zj0+UA= github.com/hashicorp/terraform-plugin-log v0.7.0 h1:SDxJUyT8TwN4l5b5/VkiTIaQgY6R+Y2BQ0sRZftGKQs= github.com/hashicorp/terraform-plugin-log v0.7.0/go.mod h1:p4R1jWBXRTvL4odmEkFfDdhUjHf9zcs/BCoNHAc7IK4= -github.com/hashicorp/terraform-plugin-mux v0.7.0 h1:wRbSYzg+v2sn5Mdee0UKm4YTt4wJG0LfSwtgNuBkglY= -github.com/hashicorp/terraform-plugin-mux v0.7.0/go.mod h1:Ae30Mc5lz4d1awtiCbHP0YyvgBeiQ00Q1nAq0U3lb+I= +github.com/hashicorp/terraform-plugin-mux v0.8.0 h1:WCTP66mZ+iIaIrCNJnjPEYnVjawTshnDJu12BcXK1EI= +github.com/hashicorp/terraform-plugin-mux v0.8.0/go.mod h1:vdW0daEi8Kd4RFJmet5Ot+SIVB/B8SwQVJiYKQwdCy8= github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.1 h1:zHcMbxY0+rFO9gY99elV/XC/UnQVg7FhRCbj1i5b7vM= github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.1/go.mod h1:+tNlb0wkfdsDJ7JEiERLz4HzM19HyiuIoGzTsM7rPpw= github.com/hashicorp/terraform-registry-address v0.1.0 h1:W6JkV9wbum+m516rCl5/NjKxCyTVaaUBbzYcMzBDO3U= From f9e8b06c2207d839f9672eebd62164ee6c50775c Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Fri, 16 Dec 2022 11:02:32 -0500 Subject: [PATCH 2/5] refactor(fw): terraform-plugin-framework v1.0.0 updates --- internal/acctest/framework.go | 10 +- internal/framework/planmodifiers/README.md | 3 - .../framework/planmodifiers/default_value.go | 43 -- .../planmodifiers/default_value_test.go | 281 -------------- .../framework/stringplanmodifier/README.md | 3 + .../stringplanmodifier/default_value.go | 43 ++ .../stringplanmodifier/default_value_test.go | 83 ++++ internal/framework/types/arn.go | 43 +- internal/framework/types/duration.go | 28 ++ internal/provider/fwprovider/provider.go | 366 ++++++++---------- internal/service/ec2/filters.go | 23 +- internal/sweep/framework.go | 10 +- internal/tags/framework.go | 18 +- 13 files changed, 368 insertions(+), 586 deletions(-) delete mode 100644 internal/framework/planmodifiers/README.md delete mode 100644 internal/framework/planmodifiers/default_value.go delete mode 100644 internal/framework/planmodifiers/default_value_test.go create mode 100644 internal/framework/stringplanmodifier/README.md create mode 100644 internal/framework/stringplanmodifier/default_value.go create mode 100644 internal/framework/stringplanmodifier/default_value_test.go diff --git a/internal/acctest/framework.go b/internal/acctest/framework.go index d7e2ebf9e8ec..f11d92b2d873 100644 --- a/internal/acctest/framework.go +++ b/internal/acctest/framework.go @@ -2,7 +2,6 @@ package acctest import ( "context" - "errors" "fmt" "log" "strings" @@ -31,14 +30,7 @@ func DeleteFrameworkResource(factory func(context.Context) (fwresource.ResourceW resource.Configure(ctx, fwresource.ConfigureRequest{ProviderData: meta}, &fwresource.ConfigureResponse{}) schemaResp := fwresource.SchemaResponse{} - if v, ok := resource.(fwresource.ResourceWithSchema); ok { - v.Schema(ctx, fwresource.SchemaRequest{}, &schemaResp) - if schemaResp.Diagnostics.HasError() { - return fwdiag.DiagnosticsError(schemaResp.Diagnostics) - } - } else { - return errors.New("resource does not implement Schema method") - } + resource.Schema(ctx, fwresource.SchemaRequest{}, &schemaResp) // Construct a simple Framework State that contains just top-level attributes. state := tfsdk.State{ diff --git a/internal/framework/planmodifiers/README.md b/internal/framework/planmodifiers/README.md deleted file mode 100644 index a520c6ccd109..000000000000 --- a/internal/framework/planmodifiers/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Terraform Plugin Framework Plan Modifiers - -This package contains Terraform Plugin Framework [plan modifiers](https://developer.hashicorp.com/terraform/plugin/framework/resources/plan-modification). diff --git a/internal/framework/planmodifiers/default_value.go b/internal/framework/planmodifiers/default_value.go deleted file mode 100644 index 265de1102439..000000000000 --- a/internal/framework/planmodifiers/default_value.go +++ /dev/null @@ -1,43 +0,0 @@ -package planmodifiers - -import ( - "context" - "fmt" - - "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" - "github.com/hashicorp/terraform-plugin-framework/types" -) - -type defaultValue struct { - value attr.Value -} - -// DefaultValue return an AttributePlanModifier that sets the specified value if the planned value is Null. -func DefaultValue(value attr.Value) tfsdk.AttributePlanModifier { - return defaultValue{ - value: value, - } -} - -func DefaultStringValue(value string) tfsdk.AttributePlanModifier { - return DefaultValue(types.StringValue(value)) -} - -func (m defaultValue) Description(context.Context) string { - return fmt.Sprintf("If value is not configured, defaults to %s", m.value) -} - -func (m defaultValue) MarkdownDescription(ctx context.Context) string { - return m.Description(ctx) -} - -func (m defaultValue) Modify(ctx context.Context, request tfsdk.ModifyAttributePlanRequest, response *tfsdk.ModifyAttributePlanResponse) { - if v, err := request.AttributePlan.ToTerraformValue(ctx); err != nil { - response.Diagnostics.AddAttributeError(request.AttributePath, "getting attribute value", err.Error()) - - return - } else if v.IsNull() { - response.AttributePlan = m.value - } -} diff --git a/internal/framework/planmodifiers/default_value_test.go b/internal/framework/planmodifiers/default_value_test.go deleted file mode 100644 index 56030d302e1c..000000000000 --- a/internal/framework/planmodifiers/default_value_test.go +++ /dev/null @@ -1,281 +0,0 @@ -package planmodifiers - -import ( - "context" - "math/big" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" - "github.com/hashicorp/terraform-plugin-framework/types" -) - -func TestDefaultValue(t *testing.T) { - t.Parallel() - - type testCase struct { - plannedValue attr.Value - currentValue attr.Value - defaultValue attr.Value - expectedValue attr.Value - expectError bool - } - tests := map[string]testCase{ - "non-default non-Null string": { - plannedValue: types.StringValue("gamma"), - currentValue: types.StringValue("beta"), - defaultValue: types.StringValue("alpha"), - expectedValue: types.StringValue("gamma"), - }, - "non-default non-Null string, current Null": { - plannedValue: types.StringValue("gamma"), - currentValue: types.StringNull(), - defaultValue: types.StringValue("alpha"), - expectedValue: types.StringValue("gamma"), - }, - "non-default Null string, current Null": { - plannedValue: types.StringNull(), - currentValue: types.StringValue("beta"), - defaultValue: types.StringValue("alpha"), - expectedValue: types.StringValue("alpha"), - }, - "default string": { - plannedValue: types.StringNull(), - currentValue: types.StringValue("alpha"), - defaultValue: types.StringValue("alpha"), - expectedValue: types.StringValue("alpha"), - }, - "default string on create": { - plannedValue: types.StringNull(), - currentValue: types.StringNull(), - defaultValue: types.StringValue("alpha"), - expectedValue: types.StringValue("alpha"), - }, - "non-default non-Null number": { - plannedValue: types.NumberValue(big.NewFloat(30)), - currentValue: types.NumberValue(big.NewFloat(10)), - defaultValue: types.NumberValue(big.NewFloat(-10)), - expectedValue: types.NumberValue(big.NewFloat(30)), - }, - "non-default non-Null number, current Null": { - plannedValue: types.NumberValue(big.NewFloat(30)), - currentValue: types.NumberNull(), - defaultValue: types.NumberValue(big.NewFloat(-10)), - expectedValue: types.NumberValue(big.NewFloat(30)), - }, - "non-default Null number, current Null": { - plannedValue: types.NumberNull(), - currentValue: types.NumberValue(big.NewFloat(10)), - defaultValue: types.NumberValue(big.NewFloat(-10)), - expectedValue: types.NumberValue(big.NewFloat(-10)), - }, - "default number": { - plannedValue: types.NumberNull(), - currentValue: types.NumberValue(big.NewFloat(-10)), - defaultValue: types.NumberValue(big.NewFloat(-10)), - expectedValue: types.NumberValue(big.NewFloat(-10)), - }, - "non-default string list": { - plannedValue: types.ListValueMust(types.StringType, []attr.Value{ - types.StringValue("POST"), - }), - currentValue: types.ListValueMust(types.StringType, []attr.Value{ - types.StringValue("PUT"), - }), - defaultValue: types.ListValueMust(types.StringType, []attr.Value{ - types.StringValue("GET"), - types.StringValue("HEAD"), - }), - expectedValue: types.ListValueMust(types.StringType, []attr.Value{ - types.StringValue("POST"), - }), - }, - "non-default string list, current out of order": { - plannedValue: types.ListNull(types.StringType), - currentValue: types.ListValueMust(types.StringType, []attr.Value{ - types.StringValue("HEAD"), - types.StringValue("GET"), - }), - defaultValue: types.ListValueMust(types.StringType, []attr.Value{ - types.StringValue("GET"), - types.StringValue("HEAD"), - }), - expectedValue: types.ListValueMust(types.StringType, []attr.Value{ - types.StringValue("GET"), - types.StringValue("HEAD"), - }), - }, - "default string list": { - plannedValue: types.ListNull(types.StringType), - currentValue: types.ListValueMust(types.StringType, []attr.Value{ - types.StringValue("GET"), - types.StringValue("HEAD"), - }), - defaultValue: types.ListValueMust(types.StringType, []attr.Value{ - types.StringValue("GET"), - types.StringValue("HEAD"), - }), - expectedValue: types.ListValueMust(types.StringType, []attr.Value{ - types.StringValue("GET"), - types.StringValue("HEAD"), - }), - }, - "non-default string set": { - plannedValue: types.SetValueMust(types.StringType, []attr.Value{ - types.StringValue("POST"), - }), - currentValue: types.SetValueMust(types.StringType, []attr.Value{ - types.StringValue("PUT"), - }), - defaultValue: types.SetValueMust(types.StringType, []attr.Value{ - types.StringValue("GET"), - types.StringValue("HEAD"), - }), - expectedValue: types.SetValueMust(types.StringType, []attr.Value{ - types.StringValue("POST"), - }), - }, - "default string set, current out of order": { - plannedValue: types.SetNull(types.StringType), - currentValue: types.SetValueMust(types.StringType, []attr.Value{ - types.StringValue("HEAD"), - types.StringValue("GET"), - }), - defaultValue: types.SetValueMust(types.StringType, []attr.Value{ - types.StringValue("GET"), - types.StringValue("HEAD"), - }), - expectedValue: types.SetValueMust(types.StringType, []attr.Value{ - types.StringValue("HEAD"), - types.StringValue("GET"), - }), - }, - "default string set": { - plannedValue: types.SetNull(types.StringType), - currentValue: types.SetValueMust(types.StringType, []attr.Value{ - types.StringValue("GET"), - types.StringValue("HEAD"), - }), - defaultValue: types.SetValueMust(types.StringType, []attr.Value{ - types.StringValue("GET"), - types.StringValue("HEAD"), - }), - expectedValue: types.SetValueMust(types.StringType, []attr.Value{ - types.StringValue("GET"), - types.StringValue("HEAD"), - }), - }, - "non-default object": { - plannedValue: types.ObjectValueMust(map[string]attr.Type{ - "value": types.StringType, - }, - map[string]attr.Value{ - "value": types.StringValue("gamma"), - }, - ), - currentValue: types.ObjectValueMust(map[string]attr.Type{ - "value": types.StringType, - }, - map[string]attr.Value{ - "value": types.StringValue("beta"), - }, - ), - defaultValue: types.ObjectValueMust(map[string]attr.Type{ - "value": types.StringType, - }, - map[string]attr.Value{ - "value": types.StringValue("alpha"), - }, - ), - expectedValue: types.ObjectValueMust(map[string]attr.Type{ - "value": types.StringType, - }, - map[string]attr.Value{ - "value": types.StringValue("gamma"), - }, - ), - }, - "non-default object, different value": { - plannedValue: types.ObjectNull(map[string]attr.Type{ - "value": types.StringType, - }), - currentValue: types.ObjectValueMust(map[string]attr.Type{ - "value": types.StringType, - }, - map[string]attr.Value{ - "value": types.StringValue("beta"), - }, - ), - defaultValue: types.ObjectValueMust(map[string]attr.Type{ - "value": types.StringType, - }, - map[string]attr.Value{ - "value": types.StringValue("alpha"), - }, - ), - expectedValue: types.ObjectValueMust(map[string]attr.Type{ - "value": types.StringType, - }, - map[string]attr.Value{ - "value": types.StringValue("alpha"), - }, - ), - }, - "default object": { - plannedValue: types.ObjectNull(map[string]attr.Type{ - "value": types.StringType, - }), - currentValue: types.ObjectValueMust(map[string]attr.Type{ - "value": types.StringType, - }, - map[string]attr.Value{ - "value": types.StringValue("alpha"), - }, - ), - defaultValue: types.ObjectValueMust(map[string]attr.Type{ - "value": types.StringType, - }, - map[string]attr.Value{ - "value": types.StringValue("alpha"), - }, - ), - expectedValue: types.ObjectValueMust(map[string]attr.Type{ - "value": types.StringType, - }, - map[string]attr.Value{ - "value": types.StringValue("alpha"), - }, - ), - }, - } - - for name, test := range tests { - name, test := name, test - t.Run(name, func(t *testing.T) { - ctx := context.Background() - request := tfsdk.ModifyAttributePlanRequest{ - AttributePath: path.Root("test"), - AttributePlan: test.plannedValue, - AttributeState: test.currentValue, - } - response := tfsdk.ModifyAttributePlanResponse{ - AttributePlan: request.AttributePlan, - } - DefaultValue(test.defaultValue).Modify(ctx, request, &response) - - if !response.Diagnostics.HasError() && test.expectError { - t.Fatal("expected error, got no error") - } - - if response.Diagnostics.HasError() && !test.expectError { - t.Fatalf("got unexpected error: %s", response.Diagnostics) - } - - if diff := cmp.Diff(response.AttributePlan, test.expectedValue); diff != "" { - t.Errorf("unexpected diff (+wanted, -got): %s", diff) - } - }) - } -} diff --git a/internal/framework/stringplanmodifier/README.md b/internal/framework/stringplanmodifier/README.md new file mode 100644 index 000000000000..7f6bf3c02094 --- /dev/null +++ b/internal/framework/stringplanmodifier/README.md @@ -0,0 +1,3 @@ +# Terraform Plugin Framework String Plan Modifiers + +This package contains Terraform Plugin Framework [string plan modifiers](https://developer.hashicorp.com/terraform/plugin/framework/resources/plan-modification). diff --git a/internal/framework/stringplanmodifier/default_value.go b/internal/framework/stringplanmodifier/default_value.go new file mode 100644 index 000000000000..90ff6d5f426e --- /dev/null +++ b/internal/framework/stringplanmodifier/default_value.go @@ -0,0 +1,43 @@ +package stringplanmodifier + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type stringDefaultValue struct { + DefaultValue types.String +} + +// StringDefaultValue return a string plan modifier that sets the specified value if the planned value is Null. +func StringDefaultValue(s types.String) planmodifier.String { + return stringDefaultValue{ + DefaultValue: s, + } +} + +func (m stringDefaultValue) Description(context.Context) string { + return fmt.Sprintf("If value is not configured, defaults to %s", m.DefaultValue) +} + +func (m stringDefaultValue) MarkdownDescription(ctx context.Context) string { + return m.Description(ctx) +} + +func (m stringDefaultValue) PlanModifyString(ctx context.Context, req planmodifier.StringRequest, resp *planmodifier.StringResponse) { + // If the attribute configuration is not null, we are done here + if !req.ConfigValue.IsNull() { + return + } + + // If the attribute plan is "known" and "not null", then a previous plan modifier in the sequence + // has already been applied, and we don't want to interfere. + if !req.PlanValue.IsUnknown() && !req.PlanValue.IsNull() { + return + } + + resp.PlanValue = m.DefaultValue +} diff --git a/internal/framework/stringplanmodifier/default_value_test.go b/internal/framework/stringplanmodifier/default_value_test.go new file mode 100644 index 000000000000..a3e3f71fb022 --- /dev/null +++ b/internal/framework/stringplanmodifier/default_value_test.go @@ -0,0 +1,83 @@ +package stringplanmodifier + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +func TestDefaultValue(t *testing.T) { + t.Parallel() + + type testCase struct { + plannedValue types.String + currentValue types.String + defaultValue types.String + expectedValue types.String + expectError bool + } + tests := map[string]testCase{ + "non-default non-Null string": { + plannedValue: types.StringValue("gamma"), + currentValue: types.StringValue("beta"), + defaultValue: types.StringValue("alpha"), + expectedValue: types.StringValue("gamma"), + }, + "non-default non-Null string, current Null": { + plannedValue: types.StringValue("gamma"), + currentValue: types.StringNull(), + defaultValue: types.StringValue("alpha"), + expectedValue: types.StringValue("gamma"), + }, + "non-default Null string, current Null": { + plannedValue: types.StringNull(), + currentValue: types.StringValue("beta"), + defaultValue: types.StringValue("alpha"), + expectedValue: types.StringValue("alpha"), + }, + "default string": { + plannedValue: types.StringNull(), + currentValue: types.StringValue("alpha"), + defaultValue: types.StringValue("alpha"), + expectedValue: types.StringValue("alpha"), + }, + "default string on create": { + plannedValue: types.StringNull(), + currentValue: types.StringNull(), + defaultValue: types.StringValue("alpha"), + expectedValue: types.StringValue("alpha"), + }, + } + + for name, test := range tests { + name, test := name, test + t.Run(name, func(t *testing.T) { + ctx := context.Background() + request := planmodifier.StringRequest{ + Path: path.Root("test"), + PlanValue: test.plannedValue, + StateValue: test.currentValue, + } + response := planmodifier.StringResponse{ + PlanValue: request.PlanValue, + } + StringDefaultValue(test.defaultValue).PlanModifyString(ctx, request, &response) + + if !response.Diagnostics.HasError() && test.expectError { + t.Fatal("expected error, got no error") + } + + if response.Diagnostics.HasError() && !test.expectError { + t.Fatalf("got unexpected error: %s", response.Diagnostics) + } + + if diff := cmp.Diff(response.PlanValue, test.expectedValue); diff != "" { + t.Errorf("unexpected diff (+wanted, -got): %s", diff) + } + }) + } +} diff --git a/internal/framework/types/arn.go b/internal/framework/types/arn.go index a5eefe0f3baf..e6faef73af01 100644 --- a/internal/framework/types/arn.go +++ b/internal/framework/types/arn.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-go/tftypes" ) @@ -27,6 +28,27 @@ func (t arnType) TerraformType(_ context.Context) tftypes.Type { return tftypes.String } +func (t arnType) ValueFromString(_ context.Context, st types.String) (basetypes.StringValuable, diag.Diagnostics) { + if st.IsNull() { + return ARNNull(), nil + } + if st.IsUnknown() { + return ARNUnknown(), nil + } + + var diags diag.Diagnostics + v, err := arn.Parse(st.ValueString()) + if err != nil { + diags.AddError( + "ARN ValueFromString Error", + fmt.Sprintf("String %s cannot be parsed as an ARN.", st), + ) + return nil, diags + } + + return ARNValue(v), diags +} + func (t arnType) ValueFromTerraform(_ context.Context, in tftypes.Value) (attr.Value, error) { if !in.IsKnown() { return ARNUnknown(), nil @@ -119,27 +141,6 @@ func (t arnType) Description() string { return `An Amazon Resource Name.` } -func (t arnType) ValueFromString(ctx context.Context, st types.String) (types.StringValuable, diag.Diagnostics) { - if st.IsNull() { - return ARNNull(), nil - } - if st.IsUnknown() { - return ARNUnknown(), nil - } - - var diags diag.Diagnostics - v, err := arn.Parse(st.String()) - if err != nil { - diags.AddError( - "ARN ValueFromString Error", - fmt.Sprintf("String %s cannot be parsed as an ARN.", st), - ) - return nil, diags - } - - return ARNValue(v), diags -} - func ARNNull() ARN { return ARN{ state: attr.ValueStateNull, diff --git a/internal/framework/types/duration.go b/internal/framework/types/duration.go index a38c7d7f8c89..59dd43dd9409 100644 --- a/internal/framework/types/duration.go +++ b/internal/framework/types/duration.go @@ -9,6 +9,8 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr/xattr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-go/tftypes" ) @@ -26,6 +28,28 @@ func (d durationType) TerraformType(_ context.Context) tftypes.Type { return tftypes.String } +func (d durationType) ValueFromString(_ context.Context, in types.String) (basetypes.StringValuable, diag.Diagnostics) { + if in.IsUnknown() { + return DurationUnknown(), nil + } + + if in.IsNull() { + return DurationNull(), nil + } + + var diags diag.Diagnostics + v, err := time.ParseDuration(in.ValueString()) + if err != nil { + diags.AddError( + "Duration Type Validation Error", + fmt.Sprintf("Value %q cannot be parsed as a Duration.", in.ValueString()), + ) + return nil, diags + } + + return DurationValue(v), nil +} + func (d durationType) ValueFromTerraform(_ context.Context, in tftypes.Value) (attr.Value, error) { if !in.IsKnown() { return DurationUnknown(), nil @@ -152,6 +176,10 @@ func (d Duration) Type(_ context.Context) attr.Type { return DurationType } +func (d Duration) ToStringValue(ctx context.Context) (types.String, diag.Diagnostics) { + return types.StringValue(d.value.String()), nil +} + // ToTerraformValue returns the data contained in the *String as a string. If // Unknown is true, it returns a tftypes.UnknownValue. If Null is true, it // returns nil. diff --git a/internal/provider/fwprovider/provider.go b/internal/provider/fwprovider/provider.go index 63ebf6c76252..641185469930 100644 --- a/internal/provider/fwprovider/provider.go +++ b/internal/provider/fwprovider/provider.go @@ -6,11 +6,12 @@ import ( "reflect" "strings" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" "github.com/hashicorp/terraform-plugin-framework/datasource" - "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/provider/schema" "github.com/hashicorp/terraform-plugin-framework/resource" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -30,276 +31,255 @@ type fwprovider struct { Primary interface{ Meta() interface{} } } -// GetSchema returns the schema for this provider's configuration. -func (p *fwprovider) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { - var diags diag.Diagnostics +func (p *fwprovider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) { + resp.TypeName = "aws" +} +// Schema returns the schema for this provider's configuration. +func (p *fwprovider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) { // This schema must match exactly the Terraform Protocol v5 (Terraform Plugin SDK v2) provider's schema. - schema := tfsdk.Schema{ - Attributes: map[string]tfsdk.Attribute{ - "access_key": { - Type: types.StringType, + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "access_key": schema.StringAttribute{ Optional: true, Description: "The access key for API operations. You can retrieve this\nfrom the 'Security & Credentials' section of the AWS console.", }, - "allowed_account_ids": { - Type: types.SetType{ElemType: types.StringType}, - Optional: true, + "allowed_account_ids": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, }, - "custom_ca_bundle": { - Type: types.StringType, + "custom_ca_bundle": schema.StringAttribute{ Optional: true, Description: "File containing custom root and intermediate certificates. Can also be configured using the `AWS_CA_BUNDLE` environment variable. (Setting `ca_bundle` in the shared config file is not supported.)", }, - "ec2_metadata_service_endpoint": { - Type: types.StringType, + "ec2_metadata_service_endpoint": schema.StringAttribute{ Optional: true, Description: "Address of the EC2 metadata service endpoint to use. Can also be configured using the `AWS_EC2_METADATA_SERVICE_ENDPOINT` environment variable.", }, - "ec2_metadata_service_endpoint_mode": { - Type: types.StringType, + "ec2_metadata_service_endpoint_mode": schema.StringAttribute{ Optional: true, Description: "Protocol to use with EC2 metadata service endpoint.Valid values are `IPv4` and `IPv6`. Can also be configured using the `AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE` environment variable.", }, - "forbidden_account_ids": { - Type: types.SetType{ElemType: types.StringType}, - Optional: true, + "forbidden_account_ids": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, }, - "http_proxy": { - Type: types.StringType, + "http_proxy": schema.StringAttribute{ Optional: true, Description: "The address of an HTTP proxy to use when accessing the AWS API. Can also be configured using the `HTTP_PROXY` or `HTTPS_PROXY` environment variables.", }, - "insecure": { - Type: types.BoolType, + "insecure": schema.BoolAttribute{ Optional: true, Description: "Explicitly allow the provider to perform \"insecure\" SSL requests. If omitted, default value is `false`", }, - "max_retries": { - Type: types.Int64Type, + "max_retries": schema.Int64Attribute{ Optional: true, Description: "The maximum number of times an AWS API request is\nbeing executed. If the API request still fails, an error is\nthrown.", }, - "profile": { - Type: types.StringType, + "profile": schema.StringAttribute{ Optional: true, Description: "The profile for API operations. If not set, the default profile\ncreated with `aws configure` will be used.", }, - "region": { - Type: types.StringType, + "region": schema.StringAttribute{ Optional: true, Description: "The region where AWS operations will take place. Examples\nare us-east-1, us-west-2, etc.", // lintignore:AWSAT003 }, - "s3_force_path_style": { - Type: types.BoolType, + "s3_force_path_style": schema.BoolAttribute{ Optional: true, Description: "Set this to true to enable the request to use path-style addressing,\ni.e., https://s3.amazonaws.com/BUCKET/KEY. By default, the S3 client will\nuse virtual hosted bucket addressing when possible\n(https://BUCKET.s3.amazonaws.com/KEY). Specific to the Amazon S3 service.", DeprecationMessage: "Use s3_use_path_style instead.", }, - "s3_use_path_style": { - Type: types.BoolType, + "s3_use_path_style": schema.BoolAttribute{ Optional: true, Description: "Set this to true to enable the request to use path-style addressing,\ni.e., https://s3.amazonaws.com/BUCKET/KEY. By default, the S3 client will\nuse virtual hosted bucket addressing when possible\n(https://BUCKET.s3.amazonaws.com/KEY). Specific to the Amazon S3 service.", }, - "secret_key": { - Type: types.StringType, + "secret_key": schema.StringAttribute{ Optional: true, Description: "The secret key for API operations. You can retrieve this\nfrom the 'Security & Credentials' section of the AWS console.", }, - "shared_config_files": { - Type: types.ListType{ElemType: types.StringType}, + "shared_config_files": schema.ListAttribute{ + ElementType: types.StringType, Optional: true, Description: "List of paths to shared config files. If not set, defaults to [~/.aws/config].", }, - "shared_credentials_file": { - Type: types.StringType, + "shared_credentials_file": schema.StringAttribute{ Optional: true, Description: "The path to the shared credentials file. If not set, defaults to ~/.aws/credentials.", DeprecationMessage: "Use shared_credentials_files instead.", }, - "shared_credentials_files": { - Type: types.ListType{ElemType: types.StringType}, + "shared_credentials_files": schema.ListAttribute{ + ElementType: types.StringType, Optional: true, Description: "List of paths to shared credentials files. If not set, defaults to [~/.aws/credentials].", }, - "skip_credentials_validation": { - Type: types.BoolType, + "skip_credentials_validation": schema.BoolAttribute{ Optional: true, Description: "Skip the credentials validation via STS API. Used for AWS API implementations that do not have STS available/implemented.", }, - "skip_get_ec2_platforms": { - Type: types.BoolType, + "skip_get_ec2_platforms": schema.BoolAttribute{ Optional: true, Description: "Skip getting the supported EC2 platforms. Used by users that don't have ec2:DescribeAccountAttributes permissions.", DeprecationMessage: `With the retirement of EC2-Classic the skip_get_ec2_platforms attribute has been deprecated and will be removed in a future version.`, }, - "skip_metadata_api_check": { - Type: types.StringType, + "skip_metadata_api_check": schema.StringAttribute{ Optional: true, Description: "Skip the AWS Metadata API check. Used for AWS API implementations that do not have a metadata api endpoint.", }, - "skip_region_validation": { - Type: types.BoolType, + "skip_region_validation": schema.BoolAttribute{ Optional: true, Description: "Skip static validation of region name. Used by users of alternative AWS-like APIs or users w/ access to regions that are not public (yet).", }, - "skip_requesting_account_id": { - Type: types.BoolType, + "skip_requesting_account_id": schema.BoolAttribute{ Optional: true, Description: "Skip requesting the account ID. Used for AWS API implementations that do not have IAM/STS API and/or metadata API.", }, - "sts_region": { - Type: types.StringType, + "sts_region": schema.StringAttribute{ Optional: true, Description: "The region where AWS STS operations will take place. Examples\nare us-east-1 and us-west-2.", // lintignore:AWSAT003 }, - "token": { - Type: types.StringType, + "token": schema.StringAttribute{ Optional: true, Description: "session token. A session token is only required if you are\nusing temporary security credentials.", }, - "use_dualstack_endpoint": { - Type: types.BoolType, + "use_dualstack_endpoint": schema.BoolAttribute{ Optional: true, Description: "Resolve an endpoint with DualStack capability", }, - "use_fips_endpoint": { - Type: types.BoolType, + "use_fips_endpoint": schema.BoolAttribute{ Optional: true, Description: "Resolve an endpoint with FIPS capability", }, }, - Blocks: map[string]tfsdk.Block{ - "assume_role": { - Attributes: map[string]tfsdk.Attribute{ - "duration": { - Type: fwtypes.DurationType, - Optional: true, - Description: "The duration, between 15 minutes and 12 hours, of the role session. Valid time units are ns, us (or µs), ms, s, h, or m.", - }, - "duration_seconds": { - Type: types.Int64Type, - Optional: true, - Description: "The duration, in seconds, of the role session.", - DeprecationMessage: "Use assume_role.duration instead", - }, - "external_id": { - Type: types.StringType, - Optional: true, - Description: "A unique identifier that might be required when you assume a role in another account.", - }, - "policy": { - Type: types.StringType, - Optional: true, - Description: "IAM Policy JSON describing further restricting permissions for the IAM Role being assumed.", - }, - "policy_arns": { - Type: types.SetType{ElemType: types.StringType}, - Optional: true, - Description: "Amazon Resource Names (ARNs) of IAM Policies describing further restricting permissions for the IAM Role being assumed.", - }, - "role_arn": { - Type: types.StringType, - Optional: true, - Description: "Amazon Resource Name (ARN) of an IAM Role to assume prior to making API calls.", - }, - "session_name": { - Type: types.StringType, - Optional: true, - Description: "An identifier for the assumed role session.", - }, - "source_identity": { - Type: types.StringType, - Optional: true, - Description: "Source identity specified by the principal assuming the role.", - }, - "tags": { - Type: types.MapType{ElemType: types.StringType}, - Optional: true, - Description: "Assume role session tags.", - }, - "transitive_tag_keys": { - Type: types.SetType{ElemType: types.StringType}, - Optional: true, - Description: "Assume role session tag keys to pass to any subsequent sessions.", + Blocks: map[string]schema.Block{ + "assume_role": schema.ListNestedBlock{ + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "duration": schema.StringAttribute{ + CustomType: fwtypes.DurationType, + Optional: true, + Description: "The duration, between 15 minutes and 12 hours, of the role session. Valid time units are ns, us (or µs), ms, s, h, or m.", + }, + "duration_seconds": schema.Int64Attribute{ + Optional: true, + Description: "The duration, in seconds, of the role session.", + DeprecationMessage: "Use assume_role.duration instead", + }, + "external_id": schema.StringAttribute{ + Optional: true, + Description: "A unique identifier that might be required when you assume a role in another account.", + }, + "policy": schema.StringAttribute{ + Optional: true, + Description: "IAM Policy JSON describing further restricting permissions for the IAM Role being assumed.", + }, + "policy_arns": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Description: "Amazon Resource Names (ARNs) of IAM Policies describing further restricting permissions for the IAM Role being assumed.", + }, + "role_arn": schema.StringAttribute{ + Optional: true, + Description: "Amazon Resource Name (ARN) of an IAM Role to assume prior to making API calls.", + }, + "session_name": schema.StringAttribute{ + Optional: true, + Description: "An identifier for the assumed role session.", + }, + "source_identity": schema.StringAttribute{ + Optional: true, + Description: "Source identity specified by the principal assuming the role.", + }, + "tags": schema.MapAttribute{ + ElementType: types.StringType, + Optional: true, + Description: "Assume role session tags.", + }, + "transitive_tag_keys": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Description: "Assume role session tag keys to pass to any subsequent sessions.", + }, }, }, - NestingMode: tfsdk.BlockNestingModeList, - MaxItems: 1, }, - "assume_role_with_web_identity": { - Attributes: map[string]tfsdk.Attribute{ - "duration": { - Type: fwtypes.DurationType, - Optional: true, - Description: "The duration, between 15 minutes and 12 hours, of the role session. Valid time units are ns, us (or µs), ms, s, h, or m.", - }, - "policy": { - Type: types.StringType, - Optional: true, - Description: "IAM Policy JSON describing further restricting permissions for the IAM Role being assumed.", - }, - "policy_arns": { - Type: types.SetType{ElemType: types.StringType}, - Optional: true, - Description: "Amazon Resource Names (ARNs) of IAM Policies describing further restricting permissions for the IAM Role being assumed.", - }, - "role_arn": { - Type: types.StringType, - Optional: true, - Description: "Amazon Resource Name (ARN) of an IAM Role to assume prior to making API calls.", - }, - "session_name": { - Type: types.StringType, - Optional: true, - Description: "An identifier for the assumed role session.", - }, - "web_identity_token": { - Type: types.StringType, - Optional: true, - }, - "web_identity_token_file": { - Type: types.StringType, - Optional: true, + "assume_role_with_web_identity": schema.ListNestedBlock{ + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "duration": schema.StringAttribute{ + CustomType: fwtypes.DurationType, + Optional: true, + Description: "The duration, between 15 minutes and 12 hours, of the role session. Valid time units are ns, us (or µs), ms, s, h, or m.", + }, + "policy": schema.StringAttribute{ + Optional: true, + Description: "IAM Policy JSON describing further restricting permissions for the IAM Role being assumed.", + }, + "policy_arns": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Description: "Amazon Resource Names (ARNs) of IAM Policies describing further restricting permissions for the IAM Role being assumed.", + }, + "role_arn": schema.StringAttribute{ + Optional: true, + Description: "Amazon Resource Name (ARN) of an IAM Role to assume prior to making API calls.", + }, + "session_name": schema.StringAttribute{ + Optional: true, + Description: "An identifier for the assumed role session.", + }, + "web_identity_token": schema.StringAttribute{ + Optional: true, + }, + "web_identity_token_file": schema.StringAttribute{ + Optional: true, + }, }, }, - NestingMode: tfsdk.BlockNestingModeList, - MaxItems: 1, }, - "default_tags": { - Attributes: map[string]tfsdk.Attribute{ - "tags": { - Type: types.MapType{ElemType: types.StringType}, - Optional: true, - Description: "Resource tags to default across all resources", - }, + "default_tags": schema.ListNestedBlock{ + Validators: []validator.List{ + listvalidator.SizeAtMost(1), }, - NestingMode: tfsdk.BlockNestingModeList, - MaxItems: 1, Description: "Configuration block with settings to default resource tags across all resources.", + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "tags": schema.MapAttribute{ + ElementType: types.StringType, + Optional: true, + Description: "Resource tags to default across all resources", + }, + }, + }, }, "endpoints": endpointsBlock(), - "ignore_tags": { - Attributes: map[string]tfsdk.Attribute{ - "key_prefixes": { - Type: types.SetType{ElemType: types.StringType}, - Optional: true, - Description: "Resource tag key prefixes to ignore across all resources.", - }, - "keys": { - Type: types.SetType{ElemType: types.StringType}, - Optional: true, - Description: "Resource tag keys to ignore across all resources.", - }, + "ignore_tags": schema.ListNestedBlock{ + Validators: []validator.List{ + listvalidator.SizeAtMost(1), }, - NestingMode: tfsdk.BlockNestingModeList, - MaxItems: 1, Description: "Configuration block with settings to ignore resource tags across all resources.", + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "key_prefixes": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Description: "Resource tag key prefixes to ignore across all resources.", + }, + "keys": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Description: "Resource tag keys to ignore across all resources.", + }, + }, + }, }, }, } - - return schema, diags } // Configure is called at the beginning of the provider lifecycle, when @@ -372,20 +352,20 @@ func (p *fwprovider) Resources(ctx context.Context) []func() resource.Resource { return resources } -func endpointsBlock() tfsdk.Block { - endpointsAttributes := make(map[string]tfsdk.Attribute) +func endpointsBlock() schema.SetNestedBlock { + endpointsAttributes := make(map[string]schema.Attribute) for _, serviceKey := range names.Aliases() { - endpointsAttributes[serviceKey] = tfsdk.Attribute{ - Type: types.StringType, + endpointsAttributes[serviceKey] = schema.StringAttribute{ Optional: true, Description: "Use this to override the default service endpoint URL", } } - return tfsdk.Block{ - Attributes: endpointsAttributes, - NestingMode: tfsdk.BlockNestingModeSet, + return schema.SetNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: endpointsAttributes, + }, } } @@ -404,14 +384,7 @@ func (w *wrappedDataSource) Metadata(ctx context.Context, request datasource.Met } func (w *wrappedDataSource) Schema(ctx context.Context, request datasource.SchemaRequest, response *datasource.SchemaResponse) { - if v, ok := w.inner.(datasource.DataSourceWithSchema); ok { - v.Schema(ctx, request, response) - return - } - response.Diagnostics.AddError( - "DataSource Schema Not Implemented", - "This data source does not support get schema. Please contact the provider developer for additional information.", - ) + w.inner.Schema(ctx, request, response) } func (w *wrappedDataSource) Read(ctx context.Context, request datasource.ReadRequest, response *datasource.ReadResponse) { @@ -442,14 +415,7 @@ func (w *wrappedResource) Metadata(ctx context.Context, request resource.Metadat } func (w *wrappedResource) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) { - if v, ok := w.inner.(resource.ResourceWithSchema); ok { - v.Schema(ctx, request, response) - return - } - response.Diagnostics.AddError( - "Resource Schema Not Implemented", - "This resource does not support get schema. Please contact the provider developer for additional information.", - ) + w.inner.Schema(ctx, request, response) } func (w *wrappedResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { diff --git a/internal/service/ec2/filters.go b/internal/service/ec2/filters.go index b7882e7a9205..e6b2b8c5c56c 100644 --- a/internal/service/ec2/filters.go +++ b/internal/service/ec2/filters.go @@ -6,6 +6,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" + datasourceschema "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -107,19 +108,19 @@ func CustomFiltersSchema() *schema.Schema { } // CustomFiltersBlock is the Plugin Framework variant of CustomFiltersSchema. -func CustomFiltersBlock() tfsdk.Block { - return tfsdk.Block{ - Attributes: map[string]tfsdk.Attribute{ - "name": { - Type: types.StringType, - Required: true, - }, - "values": { - Type: types.SetType{ElemType: types.StringType}, - Required: true, +func CustomFiltersBlock() datasourceschema.Block { + return datasourceschema.SetNestedBlock{ + NestedObject: datasourceschema.NestedBlockObject{ + Attributes: map[string]datasourceschema.Attribute{ + "name": datasourceschema.StringAttribute{ + Required: true, + }, + "values": datasourceschema.SetAttribute{ + ElementType: types.StringType, + Required: true, + }, }, }, - NestingMode: tfsdk.BlockNestingModeSet, } } diff --git a/internal/sweep/framework.go b/internal/sweep/framework.go index 5a12dbacc26b..e3b6fb20c39c 100644 --- a/internal/sweep/framework.go +++ b/internal/sweep/framework.go @@ -5,7 +5,6 @@ package sweep import ( "context" - "errors" "log" "strings" "time" @@ -70,14 +69,7 @@ func DeleteFrameworkResource(factory func(context.Context) (fwresource.ResourceW resource.Configure(ctx, fwresource.ConfigureRequest{ProviderData: meta}, &fwresource.ConfigureResponse{}) schemaResp := fwresource.SchemaResponse{} - if v, ok := resource.(fwresource.ResourceWithSchema); ok { - v.Schema(ctx, fwresource.SchemaRequest{}, &schemaResp) - if schemaResp.Diagnostics.HasError() { - return fwdiag.DiagnosticsError(schemaResp.Diagnostics) - } - } else { - return errors.New("resource does not implement Schema method") - } + resource.Schema(ctx, fwresource.SchemaRequest{}, &schemaResp) // Simple Terraform State that contains just the resource ID. state := tfsdk.State{ diff --git a/internal/tags/framework.go b/internal/tags/framework.go index 1e525beb8063..297b69347ea4 100644 --- a/internal/tags/framework.go +++ b/internal/tags/framework.go @@ -1,23 +1,23 @@ package tags import ( - "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/types" ) // Terraform Plugin Framework variants of tags schemas. -func TagsAttribute() tfsdk.Attribute { - return tfsdk.Attribute{ - Type: types.MapType{ElemType: types.StringType}, - Optional: true, +func TagsAttribute() schema.Attribute { + return schema.MapAttribute{ + ElementType: types.StringType, + Optional: true, } } -func TagsAttributeComputedOnly() tfsdk.Attribute { - return tfsdk.Attribute{ - Type: types.MapType{ElemType: types.StringType}, - Computed: true, +func TagsAttributeComputedOnly() schema.Attribute { + return schema.MapAttribute{ + ElementType: types.StringType, + Computed: true, } } From 4eb52d301306e8bc600cf2fc644d11cbf6c428f4 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Tue, 3 Jan 2023 14:32:07 -0500 Subject: [PATCH 3/5] refactor(fw): terraform-plugin-framework-timeouts v0.3.0 updates --- internal/service/resourceexplorer2/index.go | 35 +++++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/internal/service/resourceexplorer2/index.go b/internal/service/resourceexplorer2/index.go index b29a696eb9aa..5079891a06cb 100644 --- a/internal/service/resourceexplorer2/index.go +++ b/internal/service/resourceexplorer2/index.go @@ -8,7 +8,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/resourceexplorer2" awstypes "github.com/aws/aws-sdk-go-v2/service/resourceexplorer2/types" - "github.com/hashicorp/terraform-plugin-framework-timeouts/timeouts" + "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -89,8 +89,13 @@ func (r *resourceIndex) Create(ctx context.Context, request resource.CreateReque return } + createTimeout, d := data.Timeouts.Create(ctx, r.defaultCreateTimeout) + response.Diagnostics.Append(d...) + if response.Diagnostics.HasError() { + return + } + conn := r.Meta().ResourceExplorer2Client() - createTimeout := timeouts.Create(ctx, data.Timeouts, r.defaultCreateTimeout) defaultTagsConfig := r.Meta().DefaultTagsConfig ignoreTagsConfig := r.Meta().IgnoreTagsConfig tags := defaultTagsConfig.MergeTags(tftags.New(data.Tags)) @@ -206,8 +211,13 @@ func (r *resourceIndex) Update(ctx context.Context, request resource.UpdateReque return } + updateTimeout, d := new.Timeouts.Update(ctx, r.defaultUpdateTimeout) + response.Diagnostics.Append(d...) + if response.Diagnostics.HasError() { + return + } + conn := r.Meta().ResourceExplorer2Client() - updateTimeout := timeouts.Update(ctx, new.Timeouts, r.defaultUpdateTimeout) if !new.Type.Equal(old.Type) { input := &resourceexplorer2.UpdateIndexTypeInput{ @@ -250,8 +260,13 @@ func (r *resourceIndex) Delete(ctx context.Context, request resource.DeleteReque return } + deleteTimeout, d := data.Timeouts.Delete(ctx, r.defaultDeleteTimeout) + response.Diagnostics.Append(d...) + if response.Diagnostics.HasError() { + return + } + conn := r.Meta().ResourceExplorer2Client() - deleteTimeout := timeouts.Delete(ctx, data.Timeouts, r.defaultDeleteTimeout) tflog.Debug(ctx, "deleting Resource Explorer Index", map[string]interface{}{ "id": data.ID.ValueString(), @@ -282,12 +297,12 @@ func (r *resourceIndex) ModifyPlan(ctx context.Context, request resource.ModifyP } type resourceIndexData struct { - ARN types.String `tfsdk:"arn"` - ID types.String `tfsdk:"id"` - Tags types.Map `tfsdk:"tags"` - TagsAll types.Map `tfsdk:"tags_all"` - Timeouts types.Object `tfsdk:"timeouts"` - Type types.String `tfsdk:"type"` + ARN types.String `tfsdk:"arn"` + ID types.String `tfsdk:"id"` + Tags types.Map `tfsdk:"tags"` + TagsAll types.Map `tfsdk:"tags_all"` + Timeouts timeouts.Value `tfsdk:"timeouts"` + Type types.String `tfsdk:"type"` } func findIndex(ctx context.Context, conn *resourceexplorer2.Client) (*resourceexplorer2.GetIndexOutput, error) { From 7e80158971789f6ae01e61e74fd3b8a38e04110f Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Tue, 3 Jan 2023 15:43:53 -0500 Subject: [PATCH 4/5] r/aws_vpc_security_group_egress_rule: update registration --- internal/service/ec2/vpc_security_group_egress_rule.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/ec2/vpc_security_group_egress_rule.go b/internal/service/ec2/vpc_security_group_egress_rule.go index 62c8c1d0786f..ceb7cd30daea 100644 --- a/internal/service/ec2/vpc_security_group_egress_rule.go +++ b/internal/service/ec2/vpc_security_group_egress_rule.go @@ -10,7 +10,7 @@ import ( ) func init() { - //registerFrameworkResourceFactory(newResourceSecurityGroupEgressRule) + // _sp.registerFrameworkResourceFactory(newResourceSecurityGroupEgressRule) } // newResourceSecurityGroupEgressRule instantiates a new Resource for the aws_vpc_security_group_egress_rule resource. From ff5eb47cabcf8fe0c7f261759ac023468d6ee062 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Tue, 3 Jan 2023 15:44:15 -0500 Subject: [PATCH 5/5] r/aws_vpc_security_group_ingress_rule: update registration --- internal/service/ec2/vpc_security_group_ingress_rule.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/ec2/vpc_security_group_ingress_rule.go b/internal/service/ec2/vpc_security_group_ingress_rule.go index 9bdba6207c89..25d98af2433a 100644 --- a/internal/service/ec2/vpc_security_group_ingress_rule.go +++ b/internal/service/ec2/vpc_security_group_ingress_rule.go @@ -27,7 +27,7 @@ import ( ) func init() { - //registerFrameworkResourceFactory(newResourceSecurityGroupIngressRule) + // _sp.registerFrameworkResourceFactory(newResourceSecurityGroupIngressRule) } // newResourceSecurityGroupIngressRule instantiates a new Resource for the aws_vpc_security_group_ingress_rule resource.