From 77bc200c847f6e8a45d0689f58696d759756aa69 Mon Sep 17 00:00:00 2001 From: Thomas Naskali Date: Tue, 14 Oct 2025 23:13:41 +0300 Subject: [PATCH 1/2] Create new aws_sesv2_account data source --- internal/service/sesv2/account_data_source.go | 176 ++++++++++++++++++ .../service/sesv2/account_data_source_test.go | 134 +++++++++++++ .../service/sesv2/account_vdm_attributes.go | 15 -- internal/service/sesv2/service_package_gen.go | 9 +- website/docs/d/sesv2_account.html.markdown | 56 ++++++ 5 files changed, 374 insertions(+), 16 deletions(-) create mode 100644 internal/service/sesv2/account_data_source.go create mode 100644 internal/service/sesv2/account_data_source_test.go create mode 100644 website/docs/d/sesv2_account.html.markdown diff --git a/internal/service/sesv2/account_data_source.go b/internal/service/sesv2/account_data_source.go new file mode 100644 index 000000000000..5ae3c4dd38bf --- /dev/null +++ b/internal/service/sesv2/account_data_source.go @@ -0,0 +1,176 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package sesv2 + +import ( + "context" + + "github.com/aws/aws-sdk-go-v2/service/sesv2" + awstypes "github.com/aws/aws-sdk-go-v2/service/sesv2/types" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" + "github.com/hashicorp/terraform-provider-aws/internal/smerr" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" +) + +// this enum is missing from the AWS SDK sesv2/types package. +// +// See the sesv2 documentation for valid values. +// https://docs.aws.amazon.com/ses/latest/APIReference-V2/API_GetAccount.html +type EnforcementStatus string + +const ( + EnforcementStatusHealthy EnforcementStatus = "HEALTHY" + EnforcementStatusProbation EnforcementStatus = "PROBATION" + EnforcementStatusShutdown EnforcementStatus = "SHUTDOWN" +) + +func (EnforcementStatus) Values() []EnforcementStatus { + return []EnforcementStatus{ + EnforcementStatusHealthy, + EnforcementStatusProbation, + EnforcementStatusShutdown, + } +} + +// @FrameworkDataSource("aws_sesv2_account", name="Account") +func newDataSourceAccount(context.Context) (datasource.DataSourceWithConfigure, error) { + return &dataSourceAccount{}, nil +} + +const ( + DSNameAccount = "Account Data Source" +) + +type dataSourceAccount struct { + framework.DataSourceWithModel[dataSourceAccountModel] +} + +func (d *dataSourceAccount) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "dedicated_ip_auto_warmup_enabled": schema.BoolAttribute{ + Computed: true, + }, + "details": schema.ObjectAttribute{ + CustomType: fwtypes.NewObjectTypeOf[detailsModel](ctx), + Computed: true, + }, + "enforcement_status": schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[EnforcementStatus](), + Computed: true, + }, + "production_access_enabled": schema.BoolAttribute{ + Computed: true, + }, + "send_quota": schema.ObjectAttribute{ + CustomType: fwtypes.NewObjectTypeOf[sendQuotaModel](ctx), + Computed: true, + }, + "sending_enabled": schema.BoolAttribute{ + Computed: true, + }, + "suppression_attributes": schema.ObjectAttribute{ + CustomType: fwtypes.NewObjectTypeOf[suppressionAttributesModel](ctx), + Computed: true, + }, + "vdm_attributes": schema.ObjectAttribute{ + CustomType: fwtypes.NewObjectTypeOf[vdmAttributesModel](ctx), + Computed: true, + }, + }, + } +} + +func (d *dataSourceAccount) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + conn := d.Meta().SESV2Client(ctx) + + var data dataSourceAccountModel + smerr.EnrichAppend(ctx, &resp.Diagnostics, req.Config.Get(ctx, &data)) + if resp.Diagnostics.HasError() { + return + } + + out, err := findAccount(ctx, conn) + if err != nil { + smerr.AddError(ctx, &resp.Diagnostics, err, smerr.ID) + return + } + + smerr.EnrichAppend(ctx, &resp.Diagnostics, flex.Flatten(ctx, out, &data), smerr.ID) + if resp.Diagnostics.HasError() { + return + } + + smerr.EnrichAppend(ctx, &resp.Diagnostics, resp.State.Set(ctx, &data), smerr.ID) +} + +func findAccount(ctx context.Context, conn *sesv2.Client) (*sesv2.GetAccountOutput, error) { + input := &sesv2.GetAccountInput{} + + output, err := conn.GetAccount(ctx, input) + if err != nil { + return nil, err + } + + if output == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output, nil +} + +type dataSourceAccountModel struct { + framework.WithRegionModel + DedicatedIpAutoWarmupEnabled types.Bool `tfsdk:"dedicated_ip_auto_warmup_enabled"` + Details fwtypes.ObjectValueOf[detailsModel] `tfsdk:"details"` + EnforcementStatus fwtypes.StringEnum[EnforcementStatus] `tfsdk:"enforcement_status"` + ProductionAccessEnabled types.Bool `tfsdk:"production_access_enabled"` + SendQuota fwtypes.ObjectValueOf[sendQuotaModel] `tfsdk:"send_quota"` + SendingEnabled types.Bool `tfsdk:"sending_enabled"` + SuppressionAttributes fwtypes.ObjectValueOf[suppressionAttributesModel] `tfsdk:"suppression_attributes"` + VdmAttributes fwtypes.ObjectValueOf[vdmAttributesModel] `tfsdk:"vdm_attributes"` +} + +type dashboardAttributesModel struct { + EngagementMetrics fwtypes.StringEnum[awstypes.FeatureStatus] `tfsdk:"engagement_metrics"` +} + +type detailsModel struct { + AdditionalContactEmailAddresses fwtypes.SetOfString `tfsdk:"additional_contact_email_addresses"` + ContactLanguage fwtypes.StringEnum[awstypes.ContactLanguage] `tfsdk:"contact_language"` + MailType fwtypes.StringEnum[awstypes.MailType] `tfsdk:"mail_type"` + ReviewDetails fwtypes.ObjectValueOf[reviewDetailsModel] `tfsdk:"review_details"` + UseCaseDescription types.String `tfsdk:"use_case_description"` + WebsiteURL types.String `tfsdk:"website_url"` +} + +type guardianAttributesModel struct { + OptimizedSharedDelivery fwtypes.StringEnum[awstypes.FeatureStatus] `tfsdk:"optimized_shared_delivery"` +} + +type reviewDetailsModel struct { + CaseId types.String `tfsdk:"case_id"` + Status fwtypes.StringEnum[awstypes.ReviewStatus] `tfsdk:"status"` +} + +type sendQuotaModel struct { + Max24HourSend types.Float64 `tfsdk:"max_24_hour_send"` + MaxSendRate types.Float64 `tfsdk:"max_send_rate"` + SentLast24Hours types.Float64 `tfsdk:"sent_last_24_hours"` +} + +type suppressionAttributesModel struct { + SuppressedReasons fwtypes.SetOfStringEnum[awstypes.SuppressionListReason] `tfsdk:"suppressed_reasons"` +} + +type vdmAttributesModel struct { + DashboardAttributes fwtypes.ObjectValueOf[dashboardAttributesModel] `tfsdk:"dashboard_attributes"` + GuardianAttributes fwtypes.ObjectValueOf[guardianAttributesModel] `tfsdk:"guardian_attributes"` + VdmEnabled fwtypes.StringEnum[awstypes.FeatureStatus] `tfsdk:"vdm_enabled"` +} diff --git a/internal/service/sesv2/account_data_source_test.go b/internal/service/sesv2/account_data_source_test.go new file mode 100644 index 000000000000..7b61548a33d9 --- /dev/null +++ b/internal/service/sesv2/account_data_source_test.go @@ -0,0 +1,134 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package sesv2_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccSESV2AccountDataSource_default(t *testing.T) { + ctx := acctest.Context(t) + + dataSourceName := "data.aws_sesv2_account.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.SESEndpointID) + }, + ErrorCheck: acctest.ErrorCheck(t, names.SESV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: acctest.CheckDestroyNoop, + Steps: []resource.TestStep{ + { + Config: testAccAccountDataSourceConfig_default(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet(dataSourceName, "dedicated_ip_auto_warmup_enabled"), + resource.TestCheckResourceAttrSet(dataSourceName, "enforcement_status"), + resource.TestCheckResourceAttrSet(dataSourceName, "production_access_enabled"), + resource.TestCheckResourceAttrSet(dataSourceName, "send_quota.max_24_hour_send"), + resource.TestCheckResourceAttrSet(dataSourceName, "send_quota.max_send_rate"), + resource.TestCheckResourceAttrSet(dataSourceName, "send_quota.sent_last_24_hours"), + resource.TestCheckResourceAttrSet(dataSourceName, "sending_enabled"), + resource.TestCheckResourceAttrSet(dataSourceName, "suppression_attributes.suppressed_reasons.#"), + ), + }, + }, + }) +} + +func TestAccSESV2AccountDataSource_vdmAttributes(t *testing.T) { + ctx := acctest.Context(t) + + dataSourceName := "data.aws_sesv2_account.test" + resourceName := "aws_sesv2_account_vdm_attributes.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.SESEndpointID) + }, + ErrorCheck: acctest.ErrorCheck(t, names.SESV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: acctest.CheckDestroyNoop, + Steps: []resource.TestStep{ + { + Config: testAccAccountDataSourceConfig_vdmAttributes(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "vdm_attributes.vdm_enabled", resourceName, "vdm_enabled"), + resource.TestCheckResourceAttrPair(dataSourceName, "vdm_attributes.dashboard_attributes.engagement_metrics", resourceName, "dashboard_attributes.0.engagement_metrics"), + resource.TestCheckResourceAttrPair(dataSourceName, "vdm_attributes.guardian_attributes.optimized_shared_delivery", resourceName, "guardian_attributes.0.optimized_shared_delivery"), + ), + }, + }, + }) +} + +func TestAccSESV2AccountDataSource_suppressionAttributes(t *testing.T) { + ctx := acctest.Context(t) + + dataSourceName := "data.aws_sesv2_account.test" + resourceName := "aws_sesv2_account_suppression_attributes.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.SESEndpointID) + }, + ErrorCheck: acctest.ErrorCheck(t, names.SESV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: acctest.CheckDestroyNoop, + Steps: []resource.TestStep{ + { + Config: testAccAccountDataSourceConfig_suppressionAttributes(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "suppression_attributes.suppressed_reasons", resourceName, "suppressed_reasons"), + ), + }, + }, + }) +} + +func testAccAccountDataSourceConfig_default() string { + return ` +data "aws_sesv2_account" "test" { +} +` +} + +func testAccAccountDataSourceConfig_vdmAttributes() string { + return ` +resource "aws_sesv2_account_vdm_attributes" "test" { + vdm_enabled = "ENABLED" + + dashboard_attributes { + engagement_metrics = "ENABLED" + } + + guardian_attributes { + optimized_shared_delivery = "ENABLED" + } +} + +data "aws_sesv2_account" "test" { + depends_on = [ aws_sesv2_account_vdm_attributes.test ] +} +` +} + +func testAccAccountDataSourceConfig_suppressionAttributes() string { + return ` +resource "aws_sesv2_account_suppression_attributes" "test" { + suppressed_reasons = ["COMPLAINT"] +} + +data "aws_sesv2_account" "test" { + depends_on = [ aws_sesv2_account_suppression_attributes.test ] +} +` +} diff --git a/internal/service/sesv2/account_vdm_attributes.go b/internal/service/sesv2/account_vdm_attributes.go index 913283f60b31..c061897b50e2 100644 --- a/internal/service/sesv2/account_vdm_attributes.go +++ b/internal/service/sesv2/account_vdm_attributes.go @@ -172,21 +172,6 @@ func findAccountVDMAttributes(ctx context.Context, conn *sesv2.Client) (*types.V return output.VdmAttributes, nil } -func findAccount(ctx context.Context, conn *sesv2.Client) (*sesv2.GetAccountOutput, error) { - input := &sesv2.GetAccountInput{} - output, err := conn.GetAccount(ctx, input) - - if err != nil { - return nil, err - } - - if output == nil { - return nil, tfresource.NewEmptyResultError(input) - } - - return output, nil -} - func expandDashboardAttributes(tfMap map[string]any) *types.DashboardAttributes { if tfMap == nil { return nil diff --git a/internal/service/sesv2/service_package_gen.go b/internal/service/sesv2/service_package_gen.go index 178e1cb33c1a..02fdc3a8689f 100644 --- a/internal/service/sesv2/service_package_gen.go +++ b/internal/service/sesv2/service_package_gen.go @@ -18,7 +18,14 @@ import ( type servicePackage struct{} func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*inttypes.ServicePackageFrameworkDataSource { - return []*inttypes.ServicePackageFrameworkDataSource{} + return []*inttypes.ServicePackageFrameworkDataSource{ + { + Factory: newDataSourceAccount, + TypeName: "aws_sesv2_account", + Name: "Account", + Region: unique.Make(inttypes.ResourceRegionDefault()), + }, + } } func (p *servicePackage) FrameworkResources(ctx context.Context) []*inttypes.ServicePackageFrameworkResource { diff --git a/website/docs/d/sesv2_account.html.markdown b/website/docs/d/sesv2_account.html.markdown new file mode 100644 index 000000000000..1ba7f3a9873d --- /dev/null +++ b/website/docs/d/sesv2_account.html.markdown @@ -0,0 +1,56 @@ +--- +subcategory: "SESv2 (Simple Email V2)" +layout: "aws" +page_title: "AWS: aws_sesv2_account" +description: |- + Provides details about an AWS SESv2 (Simple Email V2) Account. +--- + +# Data Source: aws_sesv2_account + +Provides details about an AWS SESv2 (Simple Email V2) Account. + +## Example Usage + +### Basic Usage + +```terraform +data "aws_sesv2_account" "example" { +} +``` + +## Argument Reference + +This data source supports the following arguments: + +* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). + +## Attribute Reference + +This data source exports the following attributes in addition to the arguments above: + +* `dedicated_ip_auto_warmup_enabled` - Whether the automatic warm-up feature is enabled for associated dedicated IP addresses. +* `details` - Information about the account. + * `additional_contact_email_addresses` - Additional email addresses where updates about the review process are sent. + * `contact_language` - Preferred language for the case. Valid values are `EN` and `JA`. + * `mail_type` - Type of email sent from the account. Valid values are `MARKETING` and `TRANSACTIONAL`. + * `review_details`: Information about the latest review. + * `case_id`: Associated support center case ID (if any). + * `status`: Status of the review. Valid values are `PENDING`, `GRANTED`, `DENIED` and `FAILED`. + * `use_case_description`: Description of the types of email sent from the account. + * `website_url`: URL of a website helpful to understand the type of content sent from the account. +* `enforcement_status` - Reputation status. Valid values are `HEALTHY`, `PROBATION`, or `SHUTDOWN`. +* `production_access_enabled` - Whether production access has been granted. If the value is `false`, then the account is in the _sandbox_. +* `send_quota` - Information about the per-day and per-second sending limits. + * `max_24_hour_send` - Maximum number of emails that can be sent over a 24-hour period (_sending quota_). A value of `-1` means unlimited quota. + * `max_send_rate` - Maximum number of emails that can be sent per second (_maximum sending rate_ or _maximum TPS (transactions per second) rate_). + * `sent_last_24_hours` - Number of emails sent over the past 24 hours. +* `sending_enabled` - Whether email sending is enabled. +* `suppression_attributes` - Information about the email address suppression configuration. + * `suppressed_reasons` - List of the reasons for automatically adding email addresses to the suppression list. Valid values are `BOUNCE` and `COMPLAINT`. +* `vdm_attributes` - Information about the VDM configuration. + * `dashboard_attributes` - Additional VDM configuration settings as applicable to the Dashboard. + * `engagement_metrics` - Status of the VDM engagement metrics collection. + * `guardian_attributes` - Additional VDM configuration settings as applicable to the Guardian. + * `optimized_shared_delivery` - Status of the VDM optimized shared delivery. + * `vdm_enabled` - Status of the VDM configuration. Valid values are `ENABLED` and `DISABLED`. From 3fa06b15039a8974719ca956c31ca165b10f8d00 Mon Sep 17 00:00:00 2001 From: Thomas Naskali Date: Tue, 14 Oct 2025 23:37:26 +0300 Subject: [PATCH 2/2] Add changelog --- .changelog/44650.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/44650.txt diff --git a/.changelog/44650.txt b/.changelog/44650.txt new file mode 100644 index 000000000000..dc9a2593d390 --- /dev/null +++ b/.changelog/44650.txt @@ -0,0 +1,3 @@ +```release-note:new-data-source +aws_sesv2_account +```