Skip to content

Commit

Permalink
CR updates to remove custom period handling and add validation instead
Browse files Browse the repository at this point in the history
  • Loading branch information
anGie44 committed Jul 29, 2020
1 parent 3ae10dd commit 709b581
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 95 deletions.
29 changes: 14 additions & 15 deletions aws/resource_aws_acm_certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"log"
"regexp"
"strings"
"time"

Expand Down Expand Up @@ -58,26 +59,28 @@ func resourceAwsAcmCertificate() *schema.Resource {
},
"domain_name": {
// AWS Provider 3.0.0 aws_route53_zone references no longer contain a
// trailing period, yet to account for custom user input, a StateFunc
// is in place to prevent ACM API error
// trailing period, no longer requiring a custom StateFunc
// to prevent ACM API error
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ConflictsWith: []string{"private_key", "certificate_body", "certificate_chain"},
StateFunc: trimTrailingPeriod,
ValidateFunc: validation.StringDoesNotMatch(regexp.MustCompile(`\.$`), "cannot end with a period"),
},
"subject_alternative_names": {
Type: schema.TypeSet,
Optional: true,
Computed: true,
ForceNew: true,
Elem: &schema.Schema{
Type: schema.TypeString,
// AWS Provider 3.0.0 aws_route53_zone references no longer contain a
// trailing period, yet to account for custom user input, a StateFunc
// is in place to prevent ACM API error
StateFunc: trimTrailingPeriod,
// trailing period, no longer requiring a custom StateFunc
// to prevent ACM API error
Type: schema.TypeString,
ValidateFunc: validation.All(
validation.StringDoesNotMatch(regexp.MustCompile(`\.$`), "cannot end with a period"),
),
},
Set: schema.HashString,
ConflictsWith: []string{"private_key", "certificate_body", "certificate_chain"},
Expand Down Expand Up @@ -162,7 +165,7 @@ func resourceAwsAcmCertificate() *schema.Resource {
// Attempt to calculate the domain validation options based on domains present in domain_name and subject_alternative_names
if diff.Get("validation_method").(string) == "DNS" && (diff.HasChange("domain_name") || diff.HasChange("subject_alternative_names")) {
domainValidationOptionsList := []interface{}{map[string]interface{}{
"domain_name": strings.TrimSuffix(diff.Get("domain_name").(string), "."),
"domain_name": diff.Get("domain_name").(string),
}}

if sanSet, ok := diff.Get("subject_alternative_names").(*schema.Set); ok {
Expand Down Expand Up @@ -225,7 +228,7 @@ func resourceAwsAcmCertificateCreateImported(d *schema.ResourceData, meta interf
func resourceAwsAcmCertificateCreateRequested(d *schema.ResourceData, meta interface{}) error {
acmconn := meta.(*AWSClient).acmconn
params := &acm.RequestCertificateInput{
DomainName: aws.String(trimTrailingPeriod(d.Get("domain_name").(string))),
DomainName: aws.String(d.Get("domain_name").(string)),
IdempotencyToken: aws.String(resource.PrefixedUniqueId("tf")), // 32 character limit
Options: expandAcmCertificateOptions(d.Get("options").([]interface{})),
}
Expand Down Expand Up @@ -281,9 +284,7 @@ func resourceAwsAcmCertificateRead(d *schema.ResourceData, meta interface{}) err
return resource.NonRetryableError(fmt.Errorf("Error describing certificate: %s", err))
}

// To be consistent with other AWS services that do not accept a trailing period,
// we remove the suffix from the Fully Qualified Domain Name of the Certificate returned from the API
d.Set("domain_name", trimTrailingPeriod(aws.StringValue(resp.Certificate.DomainName)))
d.Set("domain_name", resp.Certificate.DomainName)
d.Set("arn", resp.Certificate.CertificateArn)
d.Set("certificate_authority_arn", resp.Certificate.CertificateAuthorityArn)

Expand Down Expand Up @@ -389,9 +390,7 @@ func convertValidationOptions(certificate *acm.CertificateDetail) ([]map[string]
for _, o := range certificate.DomainValidationOptions {
if o.ResourceRecord != nil {
validationOption := map[string]interface{}{
// To be consistent with other AWS services that do not accept a trailing period,
// we remove the suffix from the Fully Qualified Domain Name of the Certificate returned from the API
"domain_name": trimTrailingPeriod(aws.StringValue(o.DomainName)),
"domain_name": aws.StringValue(o.DomainName),
"resource_record_name": aws.StringValue(o.ResourceRecord.Name),
"resource_record_type": aws.StringValue(o.ResourceRecord.Type),
"resource_record_value": aws.StringValue(o.ResourceRecord.Value),
Expand Down
78 changes: 31 additions & 47 deletions aws/resource_aws_acm_certificate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func TestAccAWSAcmCertificate_emailValidation(t *testing.T) {
Config: testAccAcmCertificateConfig(domain, acm.ValidationMethodEmail),
Check: resource.ComposeTestCheckFunc(
testAccMatchResourceAttrRegionalARN(resourceName, "arn", "acm", regexp.MustCompile("certificate/.+$")),
resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(domain)),
resource.TestCheckResourceAttr(resourceName, "domain_name", domain),
resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "0"),
resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation),
resource.TestCheckResourceAttr(resourceName, "subject_alternative_names.#", "0"),
Expand Down Expand Up @@ -162,10 +162,10 @@ func TestAccAWSAcmCertificate_dnsValidation(t *testing.T) {
Config: testAccAcmCertificateConfig(domain, acm.ValidationMethodDns),
Check: resource.ComposeTestCheckFunc(
testAccMatchResourceAttrRegionalARN(resourceName, "arn", "acm", regexp.MustCompile("certificate/.+$")),
resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(domain)),
resource.TestCheckResourceAttr(resourceName, "domain_name", domain),
resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "1"),
tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{
"domain_name": trimTrailingPeriod(domain),
"domain_name": domain,
"resource_record_type": "CNAME",
}),
resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation),
Expand Down Expand Up @@ -196,10 +196,10 @@ func TestAccAWSAcmCertificate_root(t *testing.T) {
Config: testAccAcmCertificateConfig(rootDomain, acm.ValidationMethodDns),
Check: resource.ComposeTestCheckFunc(
testAccMatchResourceAttrRegionalARN(resourceName, "arn", "acm", regexp.MustCompile("certificate/.+$")),
resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(rootDomain)),
resource.TestCheckResourceAttr(resourceName, "domain_name", rootDomain),
resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "1"),
tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{
"domain_name": trimTrailingPeriod(rootDomain),
"domain_name": rootDomain,
"resource_record_type": "CNAME",
}),
resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation),
Expand Down Expand Up @@ -249,36 +249,20 @@ func TestAccAWSAcmCertificate_privateCert(t *testing.T) {
})
}

// TestAccAWSAcmCertificate_root_TrailingPeriod updated in 3.0 to account for domain_name plan-time validation
// Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13510
func TestAccAWSAcmCertificate_root_TrailingPeriod(t *testing.T) {
rootDomain := testAccAwsAcmCertificateDomainFromEnv(t)
domain := fmt.Sprintf("%s.", rootDomain)
resourceName := "aws_acm_certificate.cert"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAcmCertificateDestroy,
Steps: []resource.TestStep{
{
Config: testAccAcmCertificateConfig(domain, acm.ValidationMethodDns),
Check: resource.ComposeTestCheckFunc(
testAccMatchResourceAttrRegionalARN(resourceName, "arn", "acm", regexp.MustCompile(`certificate/.+`)),
resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(domain)),
resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "1"),
tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{
"domain_name": trimTrailingPeriod(domain),
"resource_record_type": "CNAME",
}),
resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation),
resource.TestCheckResourceAttr(resourceName, "subject_alternative_names.#", "0"),
resource.TestCheckResourceAttr(resourceName, "validation_emails.#", "0"),
resource.TestCheckResourceAttr(resourceName, "validation_method", acm.ValidationMethodDns),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
Config: testAccAcmCertificateConfig(domain, acm.ValidationMethodDns),
ExpectError: regexp.MustCompile(`config is invalid: invalid value for domain_name \(cannot end with a period\)`),
},
},
})
Expand All @@ -298,19 +282,19 @@ func TestAccAWSAcmCertificate_rootAndWildcardSan(t *testing.T) {
Config: testAccAcmCertificateConfig_subjectAlternativeNames(rootDomain, strconv.Quote(wildcardDomain), acm.ValidationMethodDns),
Check: resource.ComposeTestCheckFunc(
testAccMatchResourceAttrRegionalARN(resourceName, "arn", "acm", regexp.MustCompile("certificate/.+$")),
resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(rootDomain)),
resource.TestCheckResourceAttr(resourceName, "domain_name", rootDomain),
resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "2"),
tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{
"domain_name": trimTrailingPeriod(rootDomain),
"domain_name": rootDomain,
"resource_record_type": "CNAME",
}),
tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{
"domain_name": trimTrailingPeriod(wildcardDomain),
"domain_name": wildcardDomain,
"resource_record_type": "CNAME",
}),
resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation),
resource.TestCheckResourceAttr(resourceName, "subject_alternative_names.#", "1"),
tfawsresource.TestCheckTypeSetElemAttr(resourceName, "subject_alternative_names.*", trimTrailingPeriod(wildcardDomain)),
tfawsresource.TestCheckTypeSetElemAttr(resourceName, "subject_alternative_names.*", wildcardDomain),
resource.TestCheckResourceAttr(resourceName, "validation_emails.#", "0"),
resource.TestCheckResourceAttr(resourceName, "validation_method", acm.ValidationMethodDns),
),
Expand Down Expand Up @@ -339,19 +323,19 @@ func TestAccAWSAcmCertificate_san_single(t *testing.T) {
Config: testAccAcmCertificateConfig_subjectAlternativeNames(domain, strconv.Quote(sanDomain), acm.ValidationMethodDns),
Check: resource.ComposeTestCheckFunc(
testAccMatchResourceAttrRegionalARN(resourceName, "arn", "acm", regexp.MustCompile("certificate/.+$")),
resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(domain)),
resource.TestCheckResourceAttr(resourceName, "domain_name", domain),
resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "2"),
tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{
"domain_name": trimTrailingPeriod(domain),
"domain_name": domain,
"resource_record_type": "CNAME",
}),
tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{
"domain_name": trimTrailingPeriod(sanDomain),
"domain_name": sanDomain,
"resource_record_type": "CNAME",
}),
resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation),
resource.TestCheckResourceAttr(resourceName, "subject_alternative_names.#", "1"),
tfawsresource.TestCheckTypeSetElemAttr(resourceName, "subject_alternative_names.*", trimTrailingPeriod(sanDomain)),
tfawsresource.TestCheckTypeSetElemAttr(resourceName, "subject_alternative_names.*", sanDomain),
resource.TestCheckResourceAttr(resourceName, "validation_emails.#", "0"),
resource.TestCheckResourceAttr(resourceName, "validation_method", acm.ValidationMethodDns),
),
Expand Down Expand Up @@ -381,18 +365,18 @@ func TestAccAWSAcmCertificate_san_multiple(t *testing.T) {
Config: testAccAcmCertificateConfig_subjectAlternativeNames(domain, fmt.Sprintf("%q, %q", sanDomain1, sanDomain2), acm.ValidationMethodDns),
Check: resource.ComposeTestCheckFunc(
testAccMatchResourceAttrRegionalARN(resourceName, "arn", "acm", regexp.MustCompile("certificate/.+$")),
resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(domain)),
resource.TestCheckResourceAttr(resourceName, "domain_name", domain),
resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "3"),
tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{
"domain_name": trimTrailingPeriod(domain),
"domain_name": domain,
"resource_record_type": "CNAME",
}),
tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{
"domain_name": trimTrailingPeriod(sanDomain1),
"domain_name": sanDomain1,
"resource_record_type": "CNAME",
}),
tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{
"domain_name": trimTrailingPeriod(sanDomain2),
"domain_name": sanDomain2,
"resource_record_type": "CNAME",
}),
resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation),
Expand Down Expand Up @@ -427,14 +411,14 @@ func TestAccAWSAcmCertificate_san_TrailingPeriod(t *testing.T) {
Config: testAccAcmCertificateConfig_subjectAlternativeNames(domain, strconv.Quote(sanDomain), acm.ValidationMethodDns),
Check: resource.ComposeTestCheckFunc(
testAccMatchResourceAttrRegionalARN(resourceName, "arn", "acm", regexp.MustCompile(`certificate/.+`)),
resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(domain)),
resource.TestCheckResourceAttr(resourceName, "domain_name", domain),
resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "2"),
tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{
"domain_name": trimTrailingPeriod(domain),
"domain_name": domain,
"resource_record_type": "CNAME",
}),
tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{
"domain_name": trimTrailingPeriod(sanDomain),
"domain_name": strings.TrimSuffix(sanDomain, "."),
"resource_record_type": "CNAME",
}),
resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation),
Expand Down Expand Up @@ -467,10 +451,10 @@ func TestAccAWSAcmCertificate_wildcard(t *testing.T) {
Config: testAccAcmCertificateConfig(wildcardDomain, acm.ValidationMethodDns),
Check: resource.ComposeTestCheckFunc(
testAccMatchResourceAttrRegionalARN(resourceName, "arn", "acm", regexp.MustCompile("certificate/.+$")),
resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(wildcardDomain)),
resource.TestCheckResourceAttr(resourceName, "domain_name", wildcardDomain),
resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "1"),
tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{
"domain_name": trimTrailingPeriod(wildcardDomain),
"domain_name": wildcardDomain,
"resource_record_type": "CNAME",
}),
resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation),
Expand Down Expand Up @@ -502,14 +486,14 @@ func TestAccAWSAcmCertificate_wildcardAndRootSan(t *testing.T) {
Config: testAccAcmCertificateConfig_subjectAlternativeNames(wildcardDomain, strconv.Quote(rootDomain), acm.ValidationMethodDns),
Check: resource.ComposeTestCheckFunc(
testAccMatchResourceAttrRegionalARN(resourceName, "arn", "acm", regexp.MustCompile("certificate/.+$")),
resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(wildcardDomain)),
resource.TestCheckResourceAttr(resourceName, "domain_name", wildcardDomain),
resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "2"),
tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{
"domain_name": trimTrailingPeriod(rootDomain),
"domain_name": rootDomain,
"resource_record_type": "CNAME",
}),
tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{
"domain_name": trimTrailingPeriod(wildcardDomain),
"domain_name": wildcardDomain,
"resource_record_type": "CNAME",
}),
resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation),
Expand Down Expand Up @@ -541,10 +525,10 @@ func TestAccAWSAcmCertificate_disableCTLogging(t *testing.T) {
Config: testAccAcmCertificateConfig_disableCTLogging(rootDomain, acm.ValidationMethodDns),
Check: resource.ComposeTestCheckFunc(
testAccMatchResourceAttrRegionalARN(resourceName, "arn", "acm", regexp.MustCompile("certificate/.+$")),
resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(rootDomain)),
resource.TestCheckResourceAttr(resourceName, "domain_name", rootDomain),
resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "1"),
tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{
"domain_name": trimTrailingPeriod(rootDomain),
"domain_name": rootDomain,
"resource_record_type": "CNAME",
}),
resource.TestCheckResourceAttr(resourceName, "subject_alternative_names.#", "0"),
Expand Down
9 changes: 6 additions & 3 deletions aws/resource_aws_route53_record.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,12 @@ func resourceAwsRoute53Record() *schema.Resource {
Required: true,
ForceNew: true,
StateFunc: func(v interface{}) string {
value := trimTrailingPeriod(v)
return strings.ToLower(value)
// AWS Provider 3.0.0 aws_route53_zone references no longer contain a
// trailing period, no longer requiring the custom StateFunc
// to trim the string to prevent Route53 API error
return strings.ToLower(v.(string))
},
ValidateFunc: validation.StringDoesNotMatch(regexp.MustCompile(`\.$`), "cannot end with a period"),
},

"fqdn": {
Expand Down Expand Up @@ -919,7 +922,7 @@ func cleanRecordName(name string) string {
// If it does not, add the zone name to form a fully qualified name
// and keep AWS happy.
func expandRecordName(name, zone string) string {
rn := strings.ToLower(trimTrailingPeriod(name))
rn := strings.ToLower(name)
zone = strings.TrimSuffix(zone, ".")
if !strings.HasSuffix(rn, zone) {
if len(name) == 0 {
Expand Down
Loading

0 comments on commit 709b581

Please sign in to comment.