From 0c4c578552d4f4015da8adff6316b0bd13985245 Mon Sep 17 00:00:00 2001 From: Doug Neal Date: Sat, 1 Apr 2017 06:57:34 +0100 Subject: [PATCH] provider/aws: Implement aws_ses_domain_identity (#13098) * provider/aws: New resource: aws_ses_domain_identity Provide a resource to manage domain identities in SES. Exports the verification_code attribute which can be used to add the TXT record to the domain to complete the domain verification. * provider/aws: Acceptance tests for aws_ses_domain_identity * Resource aws_ses_domain_identity: Documentation update Provide documentation for the new resource type. --- builtin/providers/aws/provider.go | 1 + .../aws/resource_aws_ses_domain_identity.go | 99 +++++++++++++++++ .../resource_aws_ses_domain_identity_test.go | 100 ++++++++++++++++++ .../source/docs/import/importability.html.md | 1 + .../aws/r/ses_domain_identity.html.markdown | 46 ++++++++ website/source/layouts/aws.erb | 4 + 6 files changed, 251 insertions(+) create mode 100644 builtin/providers/aws/resource_aws_ses_domain_identity.go create mode 100644 builtin/providers/aws/resource_aws_ses_domain_identity_test.go create mode 100644 website/source/docs/providers/aws/r/ses_domain_identity.html.markdown diff --git a/builtin/providers/aws/provider.go b/builtin/providers/aws/provider.go index 0ad581785..e1c7d24ac 100644 --- a/builtin/providers/aws/provider.go +++ b/builtin/providers/aws/provider.go @@ -386,6 +386,7 @@ func Provider() terraform.ResourceProvider { "aws_route_table": resourceAwsRouteTable(), "aws_route_table_association": resourceAwsRouteTableAssociation(), "aws_ses_active_receipt_rule_set": resourceAwsSesActiveReceiptRuleSet(), + "aws_ses_domain_identity": resourceAwsSesDomainIdentity(), "aws_ses_receipt_filter": resourceAwsSesReceiptFilter(), "aws_ses_receipt_rule": resourceAwsSesReceiptRule(), "aws_ses_receipt_rule_set": resourceAwsSesReceiptRuleSet(), diff --git a/builtin/providers/aws/resource_aws_ses_domain_identity.go b/builtin/providers/aws/resource_aws_ses_domain_identity.go new file mode 100644 index 000000000..7eba7a187 --- /dev/null +++ b/builtin/providers/aws/resource_aws_ses_domain_identity.go @@ -0,0 +1,99 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ses" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsSesDomainIdentity() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsSesDomainIdentityCreate, + Read: resourceAwsSesDomainIdentityRead, + Delete: resourceAwsSesDomainIdentityDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "domain": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "verification_token": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceAwsSesDomainIdentityCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).sesConn + + domainName := d.Get("domain").(string) + + createOpts := &ses.VerifyDomainIdentityInput{ + Domain: aws.String(domainName), + } + + _, err := conn.VerifyDomainIdentity(createOpts) + if err != nil { + return fmt.Errorf("Error requesting SES domain identity verification: %s", err) + } + + d.SetId(domainName) + + return resourceAwsSesDomainIdentityRead(d, meta) +} + +func resourceAwsSesDomainIdentityRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).sesConn + + domainName := d.Id() + d.Set("domain", domainName) + + readOpts := &ses.GetIdentityVerificationAttributesInput{ + Identities: []*string{ + aws.String(domainName), + }, + } + + response, err := conn.GetIdentityVerificationAttributes(readOpts) + if err != nil { + log.Printf("[WARN] Error fetching identity verification attributes for %s: %s", d.Id(), err) + return err + } + + verificationAttrs, ok := response.VerificationAttributes[domainName] + if !ok { + log.Printf("[WARN] Domain not listed in response when fetching verification attributes for %s", d.Id()) + d.SetId("") + return nil + } + + d.Set("verification_token", verificationAttrs.VerificationToken) + return nil +} + +func resourceAwsSesDomainIdentityDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).sesConn + + domainName := d.Get("domain").(string) + + deleteOpts := &ses.DeleteIdentityInput{ + Identity: aws.String(domainName), + } + + _, err := conn.DeleteIdentity(deleteOpts) + if err != nil { + return fmt.Errorf("Error deleting SES domain identity: %s", err) + } + + return nil +} diff --git a/builtin/providers/aws/resource_aws_ses_domain_identity_test.go b/builtin/providers/aws/resource_aws_ses_domain_identity_test.go new file mode 100644 index 000000000..6119fa123 --- /dev/null +++ b/builtin/providers/aws/resource_aws_ses_domain_identity_test.go @@ -0,0 +1,100 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ses" + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAwsSESDomainIdentity_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsSESDomainIdentityDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: fmt.Sprintf( + testAccAwsSESDomainIdentityConfig, + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum), + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsSESDomainIdentityExists("aws_ses_domain_identity.test"), + ), + }, + }, + }) +} + +func testAccCheckAwsSESDomainIdentityDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).sesConn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_ses_domain_identity" { + continue + } + + domain := rs.Primary.ID + params := &ses.GetIdentityVerificationAttributesInput{ + Identities: []*string{ + aws.String(domain), + }, + } + + response, err := conn.GetIdentityVerificationAttributes(params) + if err != nil { + return err + } + + if response.VerificationAttributes[domain] != nil { + return fmt.Errorf("SES Domain Identity %s still exists. Failing!", domain) + } + } + + return nil +} + +func testAccCheckAwsSESDomainIdentityExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("SES Domain Identity not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("SES Domain Identity name not set") + } + + domain := rs.Primary.ID + conn := testAccProvider.Meta().(*AWSClient).sesConn + + params := &ses.GetIdentityVerificationAttributesInput{ + Identities: []*string{ + aws.String(domain), + }, + } + + response, err := conn.GetIdentityVerificationAttributes(params) + if err != nil { + return err + } + + if response.VerificationAttributes[domain] == nil { + return fmt.Errorf("SES Domain Identity %s not found in AWS", domain) + } + + return nil + } +} + +const testAccAwsSESDomainIdentityConfig = ` +resource "aws_ses_domain_identity" "test" { + domain = "%s.terraformtesting.com" +} +` diff --git a/website/source/docs/import/importability.html.md b/website/source/docs/import/importability.html.md index a9bac81e6..933c47a1d 100644 --- a/website/source/docs/import/importability.html.md +++ b/website/source/docs/import/importability.html.md @@ -92,6 +92,7 @@ To make a resource importable, please see the * aws_route_table * aws_s3_bucket * aws_security_group +* aws_ses_domain_identity * aws_ses_receipt_filter * aws_ses_receipt_rule_set * aws_simpledb_domain diff --git a/website/source/docs/providers/aws/r/ses_domain_identity.html.markdown b/website/source/docs/providers/aws/r/ses_domain_identity.html.markdown new file mode 100644 index 000000000..e005160bf --- /dev/null +++ b/website/source/docs/providers/aws/r/ses_domain_identity.html.markdown @@ -0,0 +1,46 @@ +--- +layout: "aws" +page_title: "AWS: ses_domain_identity" +sidebar_current: "docs-aws-resource-ses-domain-identity" +description: |- + Provides an SES domain identity resource +--- + +# aws\_ses\_domain_identity + +Provides an SES domain identity resource + +## Argument Reference + +The following arguments are supported: + +* `domain` - (Required) The domain name to assign to SES + +## Attributes Reference + +The following attributes are exported: + +* `verification_token` - A code which when added to the domain as a TXT record + will signal to SES that the owner of the domain has authorised SES to act on + their behalf. The domain identity will be in state "verification pending" + until this is done. See below for an example of how this might be achieved + when the domain is hosted in Route 53 and managed by Terraform. Find out + more about verifying domains in Amazon SES in the [AWS SES + docs](http://docs.aws.amazon.com/ses/latest/DeveloperGuide/verify-domains.html). + +## Example Usage + +``` +resource "aws_ses_domain_identity" "example" { + domain = "example.com" +} + +resource "aws_route53_record" "example_amazonses_verification_record" { + zone_id = "ABCDEFGHIJ123" + name = "_amazonses.example.com" + type = "TXT" + ttl = "600" + records = ["${aws_ses_domain_identity.example.verification_token}"] +} +``` + diff --git a/website/source/layouts/aws.erb b/website/source/layouts/aws.erb index d3e39f97d..75e5d546e 100644 --- a/website/source/layouts/aws.erb +++ b/website/source/layouts/aws.erb @@ -1127,6 +1127,10 @@ aws_ses_active_receipt_rule_set + > + aws_ses_domain_identity + + > aws_ses_receipt_filter