From 4068fddd5e41ccba374edc0b563eb9e63f5f556b Mon Sep 17 00:00:00 2001 From: Josh Chorlton Date: Thu, 15 Jun 2023 16:21:20 +0000 Subject: [PATCH] add data source for sesv2 email identity and email identity mail from --- internal/service/sesv2/email_identity.go | 18 ++- .../sesv2/email_identity_data_source.go | 151 ++++++++++++++++++ .../sesv2/email_identity_data_source_test.go | 56 +++++++ ...entity_mail_from_attributes_data_source.go | 67 ++++++++ ...y_mail_from_attributes_data_source_test.go | 57 +++++++ internal/service/sesv2/service_package_gen.go | 11 ++ .../docs/d/sesv2_email_identity.html.markdown | 42 +++++ ...dentity_mail_from_attributes.html.markdown | 38 +++++ .../docs/r/sesv2_email_identity.html.markdown | 2 +- 9 files changed, 434 insertions(+), 8 deletions(-) create mode 100644 internal/service/sesv2/email_identity_data_source.go create mode 100644 internal/service/sesv2/email_identity_data_source_test.go create mode 100644 internal/service/sesv2/email_identity_mail_from_attributes_data_source.go create mode 100644 internal/service/sesv2/email_identity_mail_from_attributes_data_source_test.go create mode 100644 website/docs/d/sesv2_email_identity.html.markdown create mode 100644 website/docs/d/sesv2_email_identity_mail_from_attributes.html.markdown diff --git a/internal/service/sesv2/email_identity.go b/internal/service/sesv2/email_identity.go index 854bdf2a9e2..c45604711dc 100644 --- a/internal/service/sesv2/email_identity.go +++ b/internal/service/sesv2/email_identity.go @@ -163,6 +163,16 @@ func resourceEmailIdentityCreate(ctx context.Context, d *schema.ResourceData, me return resourceEmailIdentityRead(ctx, d, meta) } +func emailIdentityNameToARN(meta interface{}, emailIdentityName string) string { + return arn.ARN{ + Partition: meta.(*conns.AWSClient).Partition, + Service: "ses", + Region: meta.(*conns.AWSClient).Region, + AccountID: meta.(*conns.AWSClient).AccountID, + Resource: fmt.Sprintf("identity/%s", emailIdentityName), + }.String() +} + func resourceEmailIdentityRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).SESV2Client(ctx) @@ -178,13 +188,7 @@ func resourceEmailIdentityRead(ctx context.Context, d *schema.ResourceData, meta return create.DiagError(names.SESV2, create.ErrActionReading, ResNameEmailIdentity, d.Id(), err) } - arn := arn.ARN{ - Partition: meta.(*conns.AWSClient).Partition, - Service: "ses", - Region: meta.(*conns.AWSClient).Region, - AccountID: meta.(*conns.AWSClient).AccountID, - Resource: fmt.Sprintf("identity/%s", d.Id()), - }.String() + arn := emailIdentityNameToARN(meta, d.Id()) d.Set("arn", arn) d.Set("configuration_set_name", out.ConfigurationSetName) diff --git a/internal/service/sesv2/email_identity_data_source.go b/internal/service/sesv2/email_identity_data_source.go new file mode 100644 index 00000000000..f72f0f125a0 --- /dev/null +++ b/internal/service/sesv2/email_identity_data_source.go @@ -0,0 +1,151 @@ +package sesv2 + +import ( + "context" + "fmt" + + "github.com/aws/aws-sdk-go-v2/service/sesv2/types" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/verify" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @SDKDataSource("aws_sesv2_email_identity") +// @Tags(identifierAttribute="arn") +func DataSourceEmailIdentity() *schema.Resource { + return &schema.Resource{ + ReadWithoutTimeout: dataSourceEmailIdentityRead, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "configuration_set_name": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 64), + }, + "dkim_signing_attributes": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "current_signing_key_length": { + Type: schema.TypeString, + Computed: true, + }, + "domain_signing_private_key": { + Type: schema.TypeString, + Optional: true, + RequiredWith: []string{"dkim_signing_attributes.0.domain_signing_selector"}, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 20480), + func(v interface{}, name string) (warns []string, errs []error) { + s := v.(string) + if !verify.IsBase64Encoded([]byte(s)) { + errs = append(errs, fmt.Errorf( + "%s: must be base64-encoded", name, + )) + } + return + }, + ), + }, + "domain_signing_selector": { + Type: schema.TypeString, + Optional: true, + RequiredWith: []string{"dkim_signing_attributes.0.domain_signing_private_key"}, + ValidateFunc: validation.StringLenBetween(1, 63), + }, + "last_key_generation_timestamp": { + Type: schema.TypeString, + Computed: true, + }, + "next_signing_key_length": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"dkim_signing_attributes.0.domain_signing_private_key", "dkim_signing_attributes.0.domain_signing_selector"}, + ValidateDiagFunc: enum.Validate[types.DkimSigningKeyLength](), + }, + "signing_attributes_origin": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + "tokens": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "email_identity": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "identity_type": { + Type: schema.TypeString, + Computed: true, + }, + names.AttrTags: tftags.TagsSchema(), + "verified_for_sending_status": { + Type: schema.TypeBool, + Computed: true, + }, + }, + } +} + +const ( + DSNameEmailIdentity = "Email Identity Data Source" +) + +func dataSourceEmailIdentityRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).SESV2Client(ctx) + + name := d.Get("email_identity").(string) + + out, err := FindEmailIdentityByID(ctx, conn, name) + if err != nil { + return create.DiagError(names.SESV2, create.ErrActionReading, DSNameEmailIdentity, name, err) + } + + arn := emailIdentityNameToARN(meta, name) + + d.SetId(name) + d.Set("arn", arn) + d.Set("configuration_set_name", out.ConfigurationSetName) + d.Set("email_identity", name) + + if out.DkimAttributes != nil { + tfMap := flattenDKIMAttributes(out.DkimAttributes) + tfMap["domain_signing_private_key"] = d.Get("dkim_signing_attributes.0.domain_signing_private_key").(string) + tfMap["domain_signing_selector"] = d.Get("dkim_signing_attributes.0.domain_signing_selector").(string) + + if err := d.Set("dkim_signing_attributes", []interface{}{tfMap}); err != nil { + return create.DiagError(names.SESV2, create.ErrActionSetting, ResNameEmailIdentity, name, err) + } + } else { + d.Set("dkim_signing_attributes", nil) + } + + d.Set("identity_type", string(out.IdentityType)) + d.Set("verified_for_sending_status", out.VerifiedForSendingStatus) + + return nil +} diff --git a/internal/service/sesv2/email_identity_data_source_test.go b/internal/service/sesv2/email_identity_data_source_test.go new file mode 100644 index 00000000000..88a1dde957d --- /dev/null +++ b/internal/service/sesv2/email_identity_data_source_test.go @@ -0,0 +1,56 @@ +package sesv2_test + +import ( + "fmt" + "testing" + + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccSESV2EmailIdentityDataSource_basic(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_sesv2_email_identity.test" + dataSourceName := "data.aws_sesv2_email_identity.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.SESV2EndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEmailIdentityDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccEmailIdentityDataSourceConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckEmailIdentityExists(ctx, dataSourceName), + resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "email_identity", dataSourceName, "email_identity"), + resource.TestCheckResourceAttrPair(resourceName, "dkim_signing_attributes.#", dataSourceName, "dkim_signing_attributes.#"), + resource.TestCheckResourceAttrPair(resourceName, "dkim_signing_attributes.0.current_signing_key_length", dataSourceName, "dkim_signing_attributes.0.current_signing_key_length"), + resource.TestCheckResourceAttrPair(resourceName, "dkim_signing_attributes.0.last_key_generation_timestamp", dataSourceName, "dkim_signing_attributes.0.last_key_generation_timestamp"), + resource.TestCheckResourceAttrPair(resourceName, "dkim_signing_attributes.0.next_signing_key_length", dataSourceName, "dkim_signing_attributes.0.next_signing_key_length"), + resource.TestCheckResourceAttrPair(resourceName, "dkim_signing_attributes.0.signing_attributes_origin", dataSourceName, "dkim_signing_attributes.0.signing_attributes_origin"), + resource.TestCheckResourceAttrPair(resourceName, "dkim_signing_attributes.0.status", dataSourceName, "dkim_signing_attributes.0.status"), + resource.TestCheckResourceAttrPair(resourceName, "dkim_signing_attributes.0.tokens.#", dataSourceName, "dkim_signing_attributes.0.tokens.#"), + resource.TestCheckResourceAttrPair(resourceName, "identity_type", dataSourceName, "identity_type"), + resource.TestCheckResourceAttrPair(resourceName, "verified_for_sending_status", dataSourceName, "verified_for_sending_status"), + ), + }, + }, + }) +} + +func testAccEmailIdentityDataSourceConfig_basic(rName string) string { + return fmt.Sprintf(` +resource "aws_sesv2_email_identity" "test" { + email_identity = %[1]q +} + +data "aws_sesv2_email_identity" "test" { + email_identity = aws_sesv2_email_identity.test.email_identity +} +`, rName) +} diff --git a/internal/service/sesv2/email_identity_mail_from_attributes_data_source.go b/internal/service/sesv2/email_identity_mail_from_attributes_data_source.go new file mode 100644 index 00000000000..4efb79ea6c7 --- /dev/null +++ b/internal/service/sesv2/email_identity_mail_from_attributes_data_source.go @@ -0,0 +1,67 @@ +package sesv2 + +import ( + "context" + + "github.com/aws/aws-sdk-go-v2/service/sesv2/types" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @SDKDataSource("aws_sesv2_email_identity_mail_from_attributes") +func DataSourceEmailIdentityMailFromAttributes() *schema.Resource { + return &schema.Resource{ + ReadWithoutTimeout: dataSourceEmailIdentityMailFromAttributesRead, + + Schema: map[string]*schema.Schema{ + "behavior_on_mx_failure": { + Type: schema.TypeString, + Optional: true, + Default: string(types.BehaviorOnMxFailureUseDefaultValue), + ValidateDiagFunc: enum.Validate[types.BehaviorOnMxFailure](), + }, + "email_identity": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "mail_from_domain": { + Type: schema.TypeString, + Optional: true, + }, + }, + } +} + +const ( + DSNameEmailIdentityMailFromAttributes = "Email Identity Mail From Attributes Data Source" +) + +func dataSourceEmailIdentityMailFromAttributesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).SESV2Client(ctx) + + name := d.Get("email_identity").(string) + + out, err := FindEmailIdentityByID(ctx, conn, name) + + if err != nil { + return create.DiagError(names.SESV2, create.ErrActionReading, ResNameEmailIdentityMailFromAttributes, name, err) + } + + d.SetId(name) + d.Set("email_identity", name) + + if out.MailFromAttributes != nil { + d.Set("behavior_on_mx_failure", out.MailFromAttributes.BehaviorOnMxFailure) + d.Set("mail_from_domain", out.MailFromAttributes.MailFromDomain) + } else { + d.Set("behavior_on_mx_failure", nil) + d.Set("mail_from_domain", nil) + } + + return nil +} diff --git a/internal/service/sesv2/email_identity_mail_from_attributes_data_source_test.go b/internal/service/sesv2/email_identity_mail_from_attributes_data_source_test.go new file mode 100644 index 00000000000..d1882f1cef3 --- /dev/null +++ b/internal/service/sesv2/email_identity_mail_from_attributes_data_source_test.go @@ -0,0 +1,57 @@ +package sesv2_test + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go-v2/service/sesv2/types" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccSESV2EmailIdentityMailFromAttributesDataSource_basic(t *testing.T) { + ctx := acctest.Context(t) + domain := acctest.RandomDomain() + mailFromDomain1 := domain.Subdomain("test1") + + rName := domain.String() + resourceName := "aws_sesv2_email_identity_mail_from_attributes.test" + dataSourceName := "data.aws_sesv2_email_identity_mail_from_attributes.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.SESV2EndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEmailIdentityDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccEmailIdentityMailFromAttributesDataSourceConfig_basic(rName, string(types.BehaviorOnMxFailureRejectMessage), mailFromDomain1.String()), + Check: resource.ComposeTestCheckFunc( + testAccCheckEmailIdentityMailFromAttributesExists(ctx, dataSourceName), + resource.TestCheckResourceAttrPair(resourceName, "email_identity", dataSourceName, "email_identity"), + resource.TestCheckResourceAttrPair(resourceName, "behavior_on_mx_failure", dataSourceName, "behavior_on_mx_failure"), + resource.TestCheckResourceAttrPair(resourceName, "mail_from_domain", dataSourceName, "mail_from_domain"), + ), + }, + }, + }) +} + +func testAccEmailIdentityMailFromAttributesDataSourceConfig_basic(rName, behaviorOnMXFailure, mailFromDomain string) string { + return fmt.Sprintf(` +resource "aws_sesv2_email_identity" "test" { + email_identity = %[1]q +} + +resource "aws_sesv2_email_identity_mail_from_attributes" "test" { + email_identity = aws_sesv2_email_identity.test.email_identity + behavior_on_mx_failure = %[2]q + mail_from_domain = %[3]q +} + +data "aws_sesv2_email_identity_mail_from_attributes" "test" { + email_identity = aws_sesv2_email_identity_mail_from_attributes.test.email_identity +} +`, rName, behaviorOnMXFailure, mailFromDomain) +} diff --git a/internal/service/sesv2/service_package_gen.go b/internal/service/sesv2/service_package_gen.go index 9ccf96a1142..7957f71d324 100644 --- a/internal/service/sesv2/service_package_gen.go +++ b/internal/service/sesv2/service_package_gen.go @@ -29,6 +29,17 @@ func (p *servicePackage) SDKDataSources(ctx context.Context) []*types.ServicePac Factory: DataSourceDedicatedIPPool, TypeName: "aws_sesv2_dedicated_ip_pool", }, + { + Factory: DataSourceEmailIdentity, + TypeName: "aws_sesv2_email_identity", + Tags: &types.ServicePackageResourceTags{ + IdentifierAttribute: "arn", + }, + }, + { + Factory: DataSourceEmailIdentityMailFromAttributes, + TypeName: "aws_sesv2_email_identity_mail_from_attributes", + }, } } diff --git a/website/docs/d/sesv2_email_identity.html.markdown b/website/docs/d/sesv2_email_identity.html.markdown new file mode 100644 index 00000000000..79e5c6d063a --- /dev/null +++ b/website/docs/d/sesv2_email_identity.html.markdown @@ -0,0 +1,42 @@ +--- +subcategory: "SESv2 (Simple Email V2)" +layout: "aws" +page_title: "AWS: aws_sesv2_email_identity" +description: |- + Terraform data source for managing an AWS SESv2 (Simple Email V2) Email Identity. +--- + +# Data Source: aws_sesv2_email_identity + +Terraform data source for managing an AWS SESv2 (Simple Email V2) Email Identity. + +## Example Usage + +### Basic Usage + +```terraform +data "aws_sesv2_email_identity" "example" { + email_identity = "example.com" +} +``` + +## Argument Reference + +The following arguments are required: + +* `email_identity` - (Required) The name of the email identity. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - ARN of the Email Identity. +* `dkim_signing_attributes` - A list of objects that contains at most one element with information about the private key and selector that you want to use to configure DKIM for the identity for Bring Your Own DKIM (BYODKIM) for the identity, or, configures the key length to be used for Easy DKIM. + * `current_signing_key_length` - [Easy DKIM] The key length of the DKIM key pair in use. + * `last_key_generation_timestamp` - [Easy DKIM] The last time a key pair was generated for this identity. + * `next_signing_key_length` - [Easy DKIM] The key length of the future DKIM key pair to be generated. This can be changed at most once per day. + * `signing_attributes_origin` - A string that indicates how DKIM was configured for the identity. `AWS_SES` indicates that DKIM was configured for the identity by using Easy DKIM. `EXTERNAL` indicates that DKIM was configured for the identity by using Bring Your Own DKIM (BYODKIM). + * `status` - Describes whether or not Amazon SES has successfully located the DKIM records in the DNS records for the domain. See the [AWS SES API v2 Reference](https://docs.aws.amazon.com/ses/latest/APIReference-V2/API_DkimAttributes.html#SES-Type-DkimAttributes-Status) for supported statuses. + * `tokens` - If you used Easy DKIM to configure DKIM authentication for the domain, then this object contains a set of unique strings that you use to create a set of CNAME records that you add to the DNS configuration for your domain. When Amazon SES detects these records in the DNS configuration for your domain, the DKIM authentication process is complete. If you configured DKIM authentication for the domain by providing your own public-private key pair, then this object contains the selector for the public key. +* `identity_type` - The email identity type. Valid values: `EMAIL_ADDRESS`, `DOMAIN`. +* `verified_for_sending_status` - Specifies whether or not the identity is verified. diff --git a/website/docs/d/sesv2_email_identity_mail_from_attributes.html.markdown b/website/docs/d/sesv2_email_identity_mail_from_attributes.html.markdown new file mode 100644 index 00000000000..01e4096b503 --- /dev/null +++ b/website/docs/d/sesv2_email_identity_mail_from_attributes.html.markdown @@ -0,0 +1,38 @@ +--- +subcategory: "SESv2 (Simple Email V2)" +layout: "aws" +page_title: "AWS: aws_sesv2_email_identity_mail_from_attributes" +description: |- + Terraform data source for managing an AWS SESv2 (Simple Email V2) Email Identity Mail From Attributes. +--- + +# Data Source: aws_sesv2_email_identity_mail_from_attributes + +Terraform data source for managing an AWS SESv2 (Simple Email V2) Email Identity Mail From Attributes. + +## Example Usage + +### Basic Usage + +```terraform +data "aws_sesv2_email_identity" "example" { + email_identity = "example.com" +} + +data "aws_sesv2_email_identity_mail_from_attributes" "example" { + email_identity = data.aws_sesv2_email_identity.example.email_identity +} +``` + +## Argument Reference + +The following arguments are required: + +* `email_identity` - (Required) The name of the email identity. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `behavior_on_mx_failure` - The action to take if the required MX record isn't found when you send an email. Valid values: `USE_DEFAULT_VALUE`, `REJECT_MESSAGE`. +* `mail_from_domain` - The custom MAIL FROM domain that you want the verified identity to use. diff --git a/website/docs/r/sesv2_email_identity.html.markdown b/website/docs/r/sesv2_email_identity.html.markdown index 01040212391..86de5537a4d 100644 --- a/website/docs/r/sesv2_email_identity.html.markdown +++ b/website/docs/r/sesv2_email_identity.html.markdown @@ -79,7 +79,7 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: * `arn` - ARN of the Email Identity. -* `dkim_signing_attributes` - An object that contains information about the private key and selector that you want to use to configure DKIM for the identity for Bring Your Own DKIM (BYODKIM) for the identity, or, configures the key length to be used for Easy DKIM. +* `dkim_signing_attributes` - A list of objects that contains at most one element with information about the private key and selector that you want to use to configure DKIM for the identity for Bring Your Own DKIM (BYODKIM) for the identity, or, configures the key length to be used for Easy DKIM. * `current_signing_key_length` - [Easy DKIM] The key length of the DKIM key pair in use. * `last_key_generation_timestamp` - [Easy DKIM] The last time a key pair was generated for this identity. * `next_signing_key_length` - [Easy DKIM] The key length of the future DKIM key pair to be generated. This can be changed at most once per day.