From ee459d6e05e6c5a68daa7becbe5fafb31c1345f4 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 14 Jul 2020 19:36:48 -0400 Subject: [PATCH 1/6] parent b69af0579e0415631faa9b77559a55a5f6e7c208 author Brian Flad 1594769808 -0400 committer Angie Pinilla 1595878294 -0400 parent b69af0579e0415631faa9b77559a55a5f6e7c208 author Brian Flad 1594769808 -0400 committer Angie Pinilla 1595878093 -0400 tests/provider: Update testacc target to error when provided example test pattern (#14091) * tests/provider: Update testacc target to error when provided example test pattern Reference: https://github.com/terraform-providers/terraform-provider-aws/blob/master/.github/PULL_REQUEST_TEMPLATE.md The pull request template suggests an example of how to run acceptance testing, but uses a placeholder example since its not feasible to reliably determine this automatically via git, etc. Also given that we have begun adding many more Go packages beyond just the top level provider one, the output can look potentially valid when it really is not meaningful: ```console $ $ make testacc TESTARGS='-run=TestAccXXX' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./... -v -count 1 -parallel 20 -run=TestAccXXX -timeout 120m ? github.com/terraform-providers/terraform-provider-aws [no test files] testing: warning: no tests to run PASS ok github.com/terraform-providers/terraform-provider-aws/aws 2.594s [no tests to run] testing: warning: no tests to run PASS ok github.com/terraform-providers/terraform-provider-aws/aws/internal/flatmap 0.409s [no tests to run] testing: warning: no tests to run PASS ok github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags 0.792s [no tests to run] testing: warning: no tests to run PASS ok github.com/terraform-providers/terraform-provider-aws/aws/internal/naming 1.619s [no tests to run] ? github.com/terraform-providers/terraform-provider-aws/aws/internal/service/apigatewayv2/waiter [no test files] testing: warning: no tests to run PASS ok github.com/terraform-providers/terraform-provider-aws/aws/internal/service/batch/equivalency 0.373s [no tests to run] ? github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/waiter [no test files] ? github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ecs/waiter [no test files] testing: warning: no tests to run PASS ok github.com/terraform-providers/terraform-provider-aws/aws/internal/service/eks/token 0.343s [no tests to run] ? github.com/terraform-providers/terraform-provider-aws/aws/internal/service/guardduty/waiter [no test files] ? github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter [no test files] ? github.com/terraform-providers/terraform-provider-aws/aws/internal/service/kinesisanalytics/waiter [no test files] ? github.com/terraform-providers/terraform-provider-aws/aws/internal/service/kms/waiter [no test files] ? github.com/terraform-providers/terraform-provider-aws/aws/internal/service/neptune/waiter [no test files] ? github.com/terraform-providers/terraform-provider-aws/aws/internal/service/rds/waiter [no test files] ? github.com/terraform-providers/terraform-provider-aws/aws/internal/service/secretsmanager/waiter [no test files] ? github.com/terraform-providers/terraform-provider-aws/aws/internal/service/servicediscovery/waiter [no test files] ? github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sfn/waiter [no test files] ? github.com/terraform-providers/terraform-provider-aws/aws/internal/service/workspaces/waiter [no test files] testing: warning: no tests to run PASS ok github.com/terraform-providers/terraform-provider-aws/aws/internal/tfawsresource 1.022s [no tests to run] ? github.com/terraform-providers/terraform-provider-aws/awsproviderlint [no test files] ? github.com/terraform-providers/terraform-provider-aws/awsproviderlint/helper/awsprovidertype/keyvaluetags [no test files] testing: warning: no tests to run PASS ok github.com/terraform-providers/terraform-provider-aws/awsproviderlint/passes 2.115s [no tests to run] testing: warning: no tests to run PASS ok github.com/terraform-providers/terraform-provider-aws/awsproviderlint/passes/AWSAT001 2.212s [no tests to run] testing: warning: no tests to run PASS ok github.com/terraform-providers/terraform-provider-aws/awsproviderlint/passes/AWSAT002 0.326s [no tests to run] testing: warning: no tests to run PASS ok github.com/terraform-providers/terraform-provider-aws/awsproviderlint/passes/AWSR001 0.412s [no tests to run] testing: warning: no tests to run PASS ok github.com/terraform-providers/terraform-provider-aws/awsproviderlint/passes/AWSR002 2.086s [no tests to run] testing: warning: no tests to run PASS ok github.com/terraform-providers/terraform-provider-aws/awsproviderlint/passes/fmtsprintfcallexpr 0.248s [no tests to run] ``` This now focuses the acceptance testing on the top level package to remove the extraneous package output and returns an error when attempting to use the example verbatim: ```console $ make testacc TESTARGS='-run=TestAccXXX' ==> Checking that code complies with gofmt requirements... Error: Skipping example acceptance testing pattern. Update TESTARGS to match the test naming in the relevant *_test.go file. For example if updating aws/resource_aws_acm_certificate.go, use the test names in aws/resource_aws_acm_certificate_test.go starting with TestAcc and up to the underscore: make testacc TESTARGS='-run=TestAccAWSAcmCertificate_' See the contributing guide for more information: https://github.com/terraform-providers/terraform-provider-aws/blob/master/docs/contributing/running-and-writing-acceptance-tests.md make: *** [testacc] Error 1 $ make testacc TESTARGS='-run=TestAccAWSAvailabilityZones_' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSAvailabilityZones_ -timeout 120m === RUN TestAccAWSAvailabilityZones_basic ... ``` * docs/provider: Remove TEST=./aws usage in running acceptance testing section resource/aws_s3_bucket: Convert region to read-only attribute (#14127) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/592 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/1656 Output from acceptance testing (NOTE: CUR data source and resource need to be tested in standalone account due to Organization permissions and appear to be failing due to new validation in the API that's not handled in the resource yet): ``` --- PASS: TestAccAWSS3Bucket_acceleration (65.86s) --- PASS: TestAccAWSS3Bucket_AclToGrant (67.94s) --- PASS: TestAccAWSS3Bucket_basic (37.25s) --- PASS: TestAccAWSS3Bucket_Bucket_EmptyString (35.95s) --- PASS: TestAccAWSS3Bucket_Cors_Delete (31.78s) --- PASS: TestAccAWSS3Bucket_Cors_EmptyOrigin (37.29s) --- PASS: TestAccAWSS3Bucket_Cors_Update (65.22s) --- PASS: TestAccAWSS3Bucket_disableDefaultEncryption_whenDefaultEncryptionIsEnabled (62.31s) --- PASS: TestAccAWSS3Bucket_enableDefaultEncryption_whenAES256IsUsed (37.28s) --- PASS: TestAccAWSS3Bucket_enableDefaultEncryption_whenTypical (43.14s) --- PASS: TestAccAWSS3Bucket_forceDestroy (31.61s) --- PASS: TestAccAWSS3Bucket_forceDestroyWithEmptyPrefixes (31.54s) --- PASS: TestAccAWSS3Bucket_forceDestroyWithObjectLockEnabled (37.95s) --- PASS: TestAccAWSS3Bucket_generatedName (35.53s) --- PASS: TestAccAWSS3Bucket_GrantToAcl (57.50s) --- PASS: TestAccAWSS3Bucket_LifecycleBasic (86.93s) --- PASS: TestAccAWSS3Bucket_LifecycleExpireMarkerOnly (62.03s) --- PASS: TestAccAWSS3Bucket_LifecycleRule_Expiration_EmptyConfigurationBlock (31.01s) --- PASS: TestAccAWSS3Bucket_Logging (55.35s) --- PASS: TestAccAWSS3Bucket_namePrefix (35.81s) --- PASS: TestAccAWSS3Bucket_objectLock (60.93s) --- PASS: TestAccAWSS3Bucket_Policy (88.67s) --- PASS: TestAccAWSS3Bucket_Replication (147.39s) --- PASS: TestAccAWSS3Bucket_ReplicationConfiguration_Rule_Destination_AccessControlTranslation (86.62s) --- PASS: TestAccAWSS3Bucket_ReplicationConfiguration_Rule_Destination_AddAccessControlTranslation (84.62s) --- PASS: TestAccAWSS3Bucket_ReplicationExpectVersioningValidationError (28.14s) --- PASS: TestAccAWSS3Bucket_ReplicationSchemaV2 (152.22s) --- PASS: TestAccAWSS3Bucket_ReplicationWithoutPrefix (52.74s) --- PASS: TestAccAWSS3Bucket_ReplicationWithoutStorageClass (51.40s) --- PASS: TestAccAWSS3Bucket_RequestPayer (63.26s) --- PASS: TestAccAWSS3Bucket_shouldFailNotFound (15.41s) --- PASS: TestAccAWSS3Bucket_tagsWithNoSystemTags (118.49s) --- PASS: TestAccAWSS3Bucket_tagsWithSystemTags (163.94s) --- PASS: TestAccAWSS3Bucket_UpdateAcl (58.70s) --- PASS: TestAccAWSS3Bucket_UpdateGrant (91.75s) --- PASS: TestAccAWSS3Bucket_Versioning (90.14s) --- PASS: TestAccAWSS3Bucket_Website_Simple (89.22s) --- PASS: TestAccAWSS3Bucket_WebsiteRedirect (86.48s) --- PASS: TestAccAWSS3Bucket_WebsiteRoutingRules (63.97s) --- PASS: TestAccAWSSsmResourceDataSync_basic (15.77s) --- PASS: TestAccAWSSsmResourceDataSync_update (28.49s) TestAccAwsCurReportDefinition_basic: testing.go:684: Step 0 error: errors during apply: Error: Error creating AWS Cost And Usage Report Definition: ValidationException: Failed to verify customer bucket permission. accountId= --OMITTED--, bucket name: tf-test-bucket-3532084976228094739, bucket region: us-east-1 TestAccDataSourceAwsCurReportDefinition_basic: testing.go:684: Step 0 error: errors during apply: Error: Error creating AWS Cost And Usage Report Definition: ValidationException: Failed to verify customer bucket permission. accountId= --OMITTED--, bucket name: tf-test-bucket-9147728765044904331, bucket region: us-east-1 ``` Update CHANGELOG for #14127 Corrects name of Workspaces Workspace sweeper let subject_alternative_names be a set re-add computed: true to subject_alternative_names attribute resource/aws_acm_certificate: Finalize subject_alternative_names change from TypeList to TypeSet Reference: https://github.com/terraform-providers/terraform-provider-aws/pull/11300 Output from acceptance testing: ``` --- PASS: TestAccAWSAcmCertificate_imported_IpAddress (11.98s) --- PASS: TestAccAWSAcmCertificate_wildcard (14.66s) --- PASS: TestAccAWSAcmCertificate_emailValidation (14.79s) --- PASS: TestAccAWSAcmCertificate_root (15.12s) --- PASS: TestAccAWSAcmCertificate_disableCTLogging (15.15s) --- PASS: TestAccAWSAcmCertificate_san_TrailingPeriod (15.80s) --- PASS: TestAccAWSAcmCertificate_wildcardAndRootSan (16.01s) --- PASS: TestAccAWSAcmCertificate_root_TrailingPeriod (16.44s) --- PASS: TestAccAWSAcmCertificate_rootAndWildcardSan (18.30s) --- PASS: TestAccAWSAcmCertificate_san_single (18.38s) --- PASS: TestAccAWSAcmCertificate_dnsValidation (18.62s) --- PASS: TestAccAWSAcmCertificate_san_multiple (19.06s) --- PASS: TestAccAWSAcmCertificate_privateCert (22.34s) --- PASS: TestAccAWSAcmCertificate_imported_DomainName (26.46s) --- PASS: TestAccAWSAcmCertificate_tags (37.20s) ``` Remove hardcoded AMI IDs from launch_config data source Removing import of aws_security_group_rule for rules associated with aws_security_group implicitly during its import. Acceptance tests updated to account for removed rules in import state check. rebased and addressed review feedback Update CHANGELOG for #12616 update documentation attributes add missing validation value for comparison_operator argument delete_on_termination on ENI has to be optional like the EBS delete_on_termination this can be optional and cannot be treated like a real bool but has to be treated as a string which can be empty or a bool representation testing all possible inputs now testing as well `delete_on_termination = ""` and `delete_on_termination = null` which both should not set the value to anything. adding upgrade instructions version 3 upgrade details Update CHANGELOG for #8612 add private_ips field change private_ips to secondary_private_ips and enable update update to using expandstringset method Update CHANGELOG for #14079 Removed hardcoded AMI IDs from AutoscalingAttachment docs/resource/aws_codebuild_webhook: Add COMMIT_MESSAGE to acceptable codebuild filter types (#14207) Co-authored-by: mikiya771 Fixes aws_lambda_alias import to set function_name attribute correctly instead of function's ARN resource/aws_lambda_alias: Finalize resource import adjustments Reference: https://github.com/terraform-providers/terraform-provider-aws/pull/12876 Output from acceptance testing: ``` --- PASS: TestAccAWSLambdaAlias_FunctionName_Name (35.53s) --- PASS: TestAccAWSLambdaAlias_basic (53.18s) --- PASS: TestAccAWSLambdaAlias_nameupdate (62.70s) --- PASS: TestAccAWSLambdaAlias_routingconfig (63.82s) ``` Update CHANGELOG for #12876 remove trailing period from domainname/name attributes update to using TrimSuffix strings method isolate changes to only route53_zone return error for singular data source Error when data.aws_ecr_repository cannot find repository Fixes https://github.com/terraform-providers/terraform-provider-aws/issues/10071. adjust error messaging return error for singular data source add angie and dirk consolidate maintainer lists Ignore hardcoded AMI because not actually used Add underscore to acceptance test names, minor naming convention fixes provider: Remove unnecessary fmt.Sprint()/fmt.Sprintf() (#14242) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/14239 Update Terraform github to v2.9.2 (#14021) * Update Terraform github to v2.9.2 * infrastructure/repository: Use organization argument instead of owner in github provider configuration Appears that the provider reverted the deprecation of the `organization` argument and inclusion of the new `owner` argument in 2.9.x, delaying until 3.0.0. Previously: ``` Error: Unsupported argument on main.tf line 14, in provider "github": 14: owner = "terraform-providers" An argument named "owner" is not expected here. ``` Co-authored-by: Renovate Bot Co-authored-by: Brian Flad add-q3-roadmap-draft add old roadmap section fix milestone link remove currently in progress in case it causes confusion r/aws_apigatewayv2_integration: suppress diff for passthrough_behavior Update CHANGELOG for #13062 Update ROADMAP.md to fix formatting omissions docs/provider: Setup and document release/* branch convention, link 2.x and earlier changelog entries (#14177) * docs/provider: Setup and document release/* branch convention, link 2.x and earlier changelog entries Reference: https://github.com/terraform-providers/terraform-provider-aws/tree/release/2.x * tests/provider: Ensure release/* branches are ran on push via GitHub Actions docs/provider: Document max_retries default (#14256) adjust error formatting and handling tests/resource/aws_s3_bucket: Add S3 Same-Region Replication acceptance test (#10170) Output from acceptance testing in AWS Commercial: ``` --- PASS: TestAccAWSS3Bucket_SameRegionReplicationSchemaV2 (52.57s) ``` Output from acceptance testing in AWS GovCloud (US): ``` --- PASS: TestAccAWSS3Bucket_SameRegionReplicationSchemaV2 (56.62s) ``` tests/resource/aws_rds_cluster: Remove aws_s3_bucket region argument from TestAccAWSRDSCluster_s3Restore (#14272) Reference: https://github.com/terraform-providers/terraform-provider-aws/pull/14127 Missed during test configuration cleanup after the referenced argument removal. Fixes the initial configuration issue, but does not fix the (still) broken test which is presumably something to do with the backup file or engine version. Previously: ``` --- FAIL: TestAccAWSRDSCluster_s3Restore (0.99s) testing.go:684: Step 0 error: config is invalid: "region": this field cannot be set ``` Output from acceptance testing: ``` === CONT TestAccAWSRDSCluster_s3Restore TestAccAWSRDSCluster_s3Restore: testing.go:684: Step 0 error: errors during apply: Error: Error waiting for RDS Cluster state to be "available": unexpected state 'migration-failed', wanted target 'available'. last error: %!s() ``` refactor resource import set virtual attributes in import func Update CHANGELOG for #10520 and #10521 update default value for min_capacity in scaling_configuration block of rds_cluster Update CHANGELOG for #14268 keep throttling disabled by default in api gateway method settings resource update import ID pattern Update CHANGELOG for #14266 add plan time validation to `self_managed_active_directory.dns_ips` add support for multi az deployment add deployment type to test add computed flag to deployment_type add docs fix docs remove computed fix multi az test disappears fix lint issue add support for `SINGLE_AZ_2` type Update website/docs/r/fsx_windows_file_system.html.markdown Co-authored-by: Simon Davis Update website/docs/r/fsx_windows_file_system.html.markdown Co-authored-by: Simon Davis Update website/docs/r/fsx_windows_file_system.html.markdown Co-authored-by: Simon Davis Update CHANGELOG.md for #12676 Fix schema set errors (#14167) * Fix schema set errors * Fix wrong attribute * Fix type * Flatten ssm parameters * resource/elasticsearch_domain: update method to set advanced_security_options (#14198) * set advanced security options only if enabled * refactor and set values depending on enabled field Co-authored-by: angie pinilla tests/provider: Enable AWSAT004 check for CI (#14216) Reference: https://github.com/terraform-providers/terraform-provider-aws/pull/14097 resource/aws_launch_configuration: Remove DescribeLaunchConfigurations retries on all errors (#14260) Reference: https://github.com/hashicorp/terraform/issues/302 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13409 Does not seem to be occurring anymore, but could require additional load to manifest. Can re-add explicit retries as necessary. Output from acceptance testing: ``` --- PASS: TestAccAWSLaunchConfiguration_withSpotPrice (11.31s) --- PASS: TestAccAWSLaunchConfiguration_ebs_noDevice (13.17s) --- PASS: TestAccAWSLaunchConfiguration_withBlockDevices (13.44s) --- PASS: TestAccAWSLaunchConfiguration_withInstanceStoreAMI (13.67s) --- PASS: TestAccAWSLaunchConfiguration_withEncryption (14.02s) --- PASS: TestAccAWSLaunchConfiguration_basic (22.34s) --- PASS: TestAccAWSLaunchConfiguration_withIAMProfile (24.19s) --- PASS: TestAccAWSLaunchConfiguration_encryptedRootBlockDevice (25.59s) --- PASS: TestAccAWSLaunchConfiguration_userData (28.60s) --- PASS: TestAccAWSLaunchConfiguration_RootBlockDevice_VolumeSize (28.91s) --- PASS: TestAccAWSLaunchConfiguration_updateEbsBlockDevices (30.96s) --- PASS: TestAccAWSLaunchConfiguration_withVpcClassicLink (32.72s) --- PASS: TestAccAWSLaunchConfiguration_RootBlockDevice_AmiDisappears (353.93s) ``` resource/aws_spot_fleet_request: Only retry RequestSpotFleet on IAM eventual consistency errors, use standard 2 minute timeout (#14265) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/7740 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13409 Output from acceptance testing: ``` --- PASS: TestAccAWSSpotFleetRequest_associatePublicIpAddress (251.97s) --- PASS: TestAccAWSSpotFleetRequest_basic (314.23s) --- PASS: TestAccAWSSpotFleetRequest_changePriceForcesNewRequest (612.33s) --- PASS: TestAccAWSSpotFleetRequest_disappears (261.47s) --- PASS: TestAccAWSSpotFleetRequest_diversifiedAllocation (403.92s) --- PASS: TestAccAWSSpotFleetRequest_fleetType (316.94s) --- PASS: TestAccAWSSpotFleetRequest_iamInstanceProfileArn (251.69s) --- PASS: TestAccAWSSpotFleetRequest_instanceInterruptionBehavior (253.29s) --- PASS: TestAccAWSSpotFleetRequest_LaunchSpecification_EbsBlockDevice_KmsKeyId (112.90s) --- PASS: TestAccAWSSpotFleetRequest_LaunchSpecification_RootBlockDevice_KmsKeyId (142.33s) --- PASS: TestAccAWSSpotFleetRequest_launchSpecToLaunchTemplate (467.97s) --- PASS: TestAccAWSSpotFleetRequest_launchTemplate (253.11s) --- PASS: TestAccAWSSpotFleetRequest_launchTemplate_multiple (254.84s) --- PASS: TestAccAWSSpotFleetRequest_launchTemplateToLaunchSpec (468.45s) --- PASS: TestAccAWSSpotFleetRequest_launchTemplateWithOverrides (253.43s) --- PASS: TestAccAWSSpotFleetRequest_lowestPriceAzInGivenList (274.51s) --- PASS: TestAccAWSSpotFleetRequest_lowestPriceAzOrSubnetInRegion (314.01s) --- PASS: TestAccAWSSpotFleetRequest_lowestPriceSubnetInGivenList (276.90s) --- PASS: TestAccAWSSpotFleetRequest_multipleInstancePools (486.46s) --- PASS: TestAccAWSSpotFleetRequest_multipleInstanceTypesInSameAz (406.36s) --- PASS: TestAccAWSSpotFleetRequest_multipleInstanceTypesInSameSubnet (231.26s) --- PASS: TestAccAWSSpotFleetRequest_overriddingSpotPrice (295.29s) --- PASS: TestAccAWSSpotFleetRequest_placementTenancyAndGroup (57.48s) --- PASS: TestAccAWSSpotFleetRequest_tags (342.55s) --- PASS: TestAccAWSSpotFleetRequest_updateExcessCapacityTerminationPolicy (597.13s) --- PASS: TestAccAWSSpotFleetRequest_updateTargetCapacity (753.34s) --- PASS: TestAccAWSSpotFleetRequest_withEBSDisk (255.16s) --- PASS: TestAccAWSSpotFleetRequest_WithELBs (277.96s) --- PASS: TestAccAWSSpotFleetRequest_withoutSpotPrice (232.56s) --- PASS: TestAccAWSSpotFleetRequest_withTags (282.39s) --- PASS: TestAccAWSSpotFleetRequest_WithTargetGroups (427.61s) --- PASS: TestAccAWSSpotFleetRequest_withWeightedCapacity (335.33s) ``` Update CHANGELOG for #14265 resource/aws_codepipeline: Only retry CreatePipeline errors for IAM eventual consistency (#14264) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13409 Output from acceptance testing: ``` --- PASS: TestAccAWSCodePipeline_emptyStageArtifacts (33.11s) --- PASS: TestAccAWSCodePipeline_WithNamespace (35.13s) --- PASS: TestAccAWSCodePipeline_multiregion_basic (36.83s) --- PASS: TestAccAWSCodePipeline_deployWithServiceRole (42.85s) --- PASS: TestAccAWSCodePipeline_basic (57.83s) --- PASS: TestAccAWSCodePipeline_multiregion_Update (61.32s) --- PASS: TestAccAWSCodePipeline_tags (76.28s) --- PASS: TestAccAWSCodePipeline_multiregion_ConvertSingleRegion (79.20s) ``` Update CHANGELOG for #14264 resource/aws_ssm_activation: Only retry CreateActivation on IAM eventual consistency error, allow retries for standard 2 minutes (#14263) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13409 API does not seem to validate IAM Role permissions on creation. Output from acceptance testing: ``` --- PASS: TestAccAWSSSMActivation_expirationDate (19.17s) --- PASS: TestAccAWSSSMActivation_disappears (25.22s) --- PASS: TestAccAWSSSMActivation_basic (27.39s) --- PASS: TestAccAWSSSMActivation_update (37.23s) ``` Update CHANGELOG for #14263 resource/aws_network_acl_rule: Immediately return DescribeNetworkAcls errors on creation (#14261) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13409 Output from acceptance testing: ``` --- PASS: TestAccAWSNetworkAclRule_allProtocol (44.33s) --- PASS: TestAccAWSNetworkAclRule_basic (32.50s) --- PASS: TestAccAWSNetworkAclRule_disappears (32.83s) --- PASS: TestAccAWSNetworkAclRule_disappears_NetworkAcl (27.16s) --- PASS: TestAccAWSNetworkAclRule_ingressEgressSameNumberDisappears (30.24s) --- PASS: TestAccAWSNetworkAclRule_ipv6 (29.23s) --- PASS: TestAccAWSNetworkAclRule_ipv6ICMP (28.65s) --- PASS: TestAccAWSNetworkAclRule_ipv6VpcAssignGeneratedIpv6CidrBlockUpdate (47.71s) --- PASS: TestAccAWSNetworkAclRule_missingParam (15.14s) --- PASS: TestAccAWSNetworkAclRule_tcpProtocol (40.32s) ``` Update CHANGELOG for #14261 Add function to check TypeSet pairs Add unit tests for TestCheckTypeSetElemAttrPair tests/resource/aws_rds_cluster: Fix TestAccAWSRDSCluster_EngineVersion (#14286) isolate changes to only route53_record resource update additional domian name example in upgrade guide Co-authored-by: Brian Flad update with CR comments isolate changes to only resolver rule isolate changes to only acm_certificate isolate changes to only ses_domain_identity re-add trailing period acctest merge with parent branch and update statefuncs to use global method update statefuncs to use global method and update tests w/trailingp period domains r/aws_apigatewayv2_stage: Make deployment_id a computed attribute. Update CHANGELOG.md for #13644 bump to go v1.14.5 r/aws_apigatewayv2_integration: Add 'request_parameters' attribute. Update CHANGELOG.md for #14080 r/aws_apigatewayv2_route: Update route key. Update CHANGELOG.md for #13833 Revert "Remove 'tls_config' attribute. It doesn't seem to do anything right now." This reverts commit ffbce32f931a9b33adc8407a267ba176c510bd44. r/aws_apigatewayv2_integration: Test HTTP API VPC Link integration. r/aws_apigatewayv2_integration: Additional import test step in 'TestAccAWSAPIGatewayV2Integration_VpcLinkHttp'. Update CHANGELOG.md Update CHANGELOG.md for #13013 Update CHANGELOG.md add atleastoneof property to filter attributes Update CHANGELOG for #14230 Remove hardcoded AMI and AZ Improve static check for hardcoded partition in ARN resource/aws_lambda_function: Increase IAM retry timeout for create to 2 minutes (#14291) References: * https://github.com/terraform-providers/terraform-provider-aws/issues/14285 Increased the retry timeout for eventual consistency IAM errors during a lambda function create from 1 minute to 2 minute. Output from acceptance testing: ``` make testacc TEST=./aws TESTARGS='-run=TestAccAWSLambdaFunction_' ... --- PASS: TestAccAWSLambdaFunction_basic (28.86s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_java8 (34.46s) --- PASS: TestAccAWSLambdaFunction_DeadLetterConfigUpdated (160.32s) --- PASS: TestAccAWSLambdaFunction_VpcConfig_ProperIamDependencies (208.54s) --- PASS: TestAccAWSLambdaFunction_VPC_withInvocation (567.54s) --- PASS: TestAccAWSLambdaFunction_VPCRemoval (596.13s) --- PASS: TestAccAWSLambdaFunction_LayersUpdate (49.02s) --- PASS: TestAccAWSLambdaFunction_VPC (362.84s) --- PASS: TestAccAWSLambdaFunction_VPCUpdate (797.25s) --- PASS: TestAccAWSLambdaFunction_nilDeadLetterConfig (120.01s) --- PASS: TestAccAWSLambdaFunction_DeadLetterConfig (51.30s) --- PASS: TestAccAWSLambdaFunction_envVariables (153.15s) --- PASS: TestAccAWSLambdaFunction_versioned (39.16s) --- PASS: TestAccAWSLambdaFunction_versionedUpdate (61.80s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_python37 (31.16s) --- PASS: TestAccAWSLambdaFunction_encryptedEnvVariables (51.77s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_dotnetcore31 (36.20s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_ruby27 (40.86s) --- PASS: TestAccAWSLambdaFunction_Layers (38.54s) --- PASS: TestAccAWSLambdaFunction_tracingConfig (51.87s) --- PASS: TestAccAWSLambdaFunction_KmsKeyArn_NoEnvironmentVariables (36.57s) --- PASS: TestAccAWSLambdaFunction_concurrencyCycle (54.03s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_ruby25 (36.53s) --- PASS: TestAccAWSLambdaFunction_expectFilenameAndS3Attributes (13.34s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_python38 (28.27s) --- PASS: TestAccAWSLambdaFunction_tags (51.19s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_java11 (36.59s) --- PASS: TestAccAWSLambdaFunction_updateRuntime (51.42s) --- PASS: TestAccAWSLambdaFunction_s3Update_unversioned (43.77s) --- PASS: TestAccAWSLambdaFunction_localUpdate (39.80s) --- PASS: TestAccAWSLambdaFunction_s3Update_basic (44.15s) --- PASS: TestAccAWSLambdaFunction_localUpdate_nameOnly (40.02s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_python36 (32.09s) --- PASS: TestAccAWSLambdaFunction_FileSystemConfig (721.87s) --- PASS: TestAccAWSLambdaFunction_s3 (31.68s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_provided (36.48s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_python27 (33.63s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_NodeJs10x (38.17s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_noRuntime (0.91s) --- PASS: TestAccAWSLambdaFunction_concurrency (46.63s) --- PASS: TestAccAWSLambdaFunction_EmptyVpcConfig (38.38s) --- PASS: TestAccAWSLambdaFunction_disappears (36.13s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_NodeJs12x (38.47s) ``` Update CHANGELOG for #14291 error when iops provided for unsupported type improve upgrade docs for iops Update CHANGELOG for #14310 Update CHANGELOG with Go versioning Remove hardcoded AMIs and AZs Remove hardcoded AMIs and AZs Removed hardcoded AMIs and AZs Remove hardcoded AMI and AZ Remove hardcoded AMI r/aws_apigatewayv2_stage: 'data_trace_enabled' and 'logging_level' are only valid for WebSocket APIs. r/aws_apigatewayv2_stage: No need for diff-suppression for new resources. r/aws_apigatewayv2_stage: Additional route_settings and default_route_settings test cases. r/aws_apigatewayv2_stage: Add computed 'api_protocol_type' attribute. r/aws_apigatewayv2_stage: Pass API protocol type to 'flattenApiGatewayV2RouteSettings'. Revert "r/aws_apigatewayv2_stage: Pass API protocol type to 'flattenApiGatewayV2RouteSettings'." This reverts commit 9337272b7842879cdbae5be19ec076bea314b20c. Revert "r/aws_apigatewayv2_stage: Add computed 'api_protocol_type' attribute." This reverts commit a7eb7cf9976ecabb04696dbe2f39805cc0ec1401. Fix mess from rebase. r/aws_apigatewayv2_stage: Change 'route_setting.logging_level' to computed to address different defaults for WebSocket vs. HTTP. Update CHANGELOG.md for #13809 resource/aws_acm_certificate: Convert domain_validation_options to TypeSet and calculate elements during plan (#14199) * resource/aws_acm_certificate: Convert domain_validation_options to TypeSet and calculate elements during plan Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/8531 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/10098 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/10404 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13053 Output from acceptance testing: ``` --- PASS: TestAccAWSAcmCertificate_imported_IpAddress (11.48s) --- PASS: TestAccAWSAcmCertificate_rootAndWildcardSan (15.53s) --- PASS: TestAccAWSAcmCertificate_root_TrailingPeriod (15.53s) --- PASS: TestAccAWSAcmCertificate_root (15.62s) --- PASS: TestAccAWSAcmCertificate_emailValidation (15.91s) --- PASS: TestAccAWSAcmCertificate_san_TrailingPeriod (16.38s) --- PASS: TestAccAWSAcmCertificate_wildcardAndRootSan (16.43s) --- PASS: TestAccAWSAcmCertificate_san_single (16.51s) --- PASS: TestAccAWSAcmCertificate_dnsValidation (16.85s) --- PASS: TestAccAWSAcmCertificate_disableCTLogging (17.06s) --- PASS: TestAccAWSAcmCertificate_wildcard (18.71s) --- PASS: TestAccAWSAcmCertificate_san_multiple (19.49s) --- PASS: TestAccAWSAcmCertificate_privateCert (20.85s) --- PASS: TestAccAWSAcmCertificate_imported_DomainName (26.86s) --- PASS: TestAccAWSAcmCertificate_tags (42.99s) --- PASS: TestAccAWSAcmCertificateValidation_validationRecordFqdnsEmail (11.56s) --- PASS: TestAccAWSAcmCertificateValidation_timeout (19.20s) --- PASS: TestAccAWSAcmCertificateValidation_validationRecordFqdns (107.31s) --- PASS: TestAccAWSAcmCertificateValidation_validationRecordFqdnsSan (110.62s) --- PASS: TestAccAWSAcmCertificateValidation_basic (143.58s) --- PASS: TestAccAWSAcmCertificateValidation_validationRecordFqdnsWildcardAndRoot (153.05s) --- PASS: TestAccAWSAcmCertificateValidation_validationRecordFqdnsRoot (212.21s) --- PASS: TestAccAWSAcmCertificateValidation_validationRecordFqdnsRootAndWildcard (212.95s) --- PASS: TestAccAWSAcmCertificateValidation_validationRecordFqdnsWildcard (247.43s) ``` Please note that this was also tested manually with a few iterations of this configuration: ```hcl terraform { required_providers { aws = "2.70.0" } required_version = "0.12.28" } provider "aws" { region = "us-east-2" } variable "public_root_domain" { description = "Publicly accessible domain for ACM testing" type = string } data "aws_route53_zone" "public_root_domain" { name = var.public_root_domain } resource "aws_acm_certificate" "new" { domain_name = "new.${var.public_root_domain}" subject_alternative_names = [ "new1.${var.public_root_domain}", "new2.${var.public_root_domain}", "new3.${var.public_root_domain}", ] validation_method = "DNS" } resource "aws_route53_record" "new" { for_each = { for dvo in aws_acm_certificate.new.domain_validation_options: dvo.domain_name => { name = dvo.resource_record_name record = dvo.resource_record_value type = dvo.resource_record_type } } allow_overwrite = true name = each.value.name records = [each.value.record] ttl = 60 type = each.value.type zone_id = data.aws_route53_zone.public_root_domain.zone_id } resource "aws_acm_certificate_validation" "new" { certificate_arn = aws_acm_certificate.new.arn validation_record_fqdns = [for record in aws_route53_record.new: record.fqdn] } resource "aws_acm_certificate" "wildcard" { domain_name = var.public_root_domain subject_alternative_names = ["*.${var.public_root_domain}"] validation_method = "DNS" } resource "aws_route53_record" "wildcard" { for_each = { for dvo in aws_acm_certificate.wildcard.domain_validation_options: dvo.domain_name => { name = dvo.resource_record_name record = dvo.resource_record_value type = dvo.resource_record_type } } allow_overwrite = true name = each.value.name records = [each.value.record] ttl = 60 type = each.value.type zone_id = data.aws_route53_zone.public_root_domain.zone_id } resource "aws_acm_certificate_validation" "wildcard" { certificate_arn = aws_acm_certificate.wildcard.arn validation_record_fqdns = [for record in aws_route53_record.wildcard: record.fqdn] } ``` * docs/service/acm: Fix terrafmt reports Previously: ``` website/docs/r/acm_certificate.html.markdown:83 website/docs/r/acm_certificate_validation.html.markdown:25 website/docs/r/acm_certificate_validation.html.markdown:67 ``` Update CHANGELOG for #14199 Implement Disappears test for API Gateway resources (#13243) * add disappears test case for APIGW API Key * add disappears test case for APIGW Authorizer * add disappears test case for APIGW Base Path * add disappears test case for APIGW Client Cert * add disappears test case for APIGW Deployment * add disappears test case for APIGW Doc Part * add disappears test case for APIGW Doc Ver * add disappears test case for APIGW Domain Name * add disappears test case for APIGW Gateway Response * add disappears test case for APIGW Integration Response * add disappears test case for APIGW Integration * add disappears test case for APIGW Method * add disappears test case for APIGW Method Response * add disappears test case for APIGW Method Settings * add disappears test case for APIGW Model * add disappears test case for APIGW Request Validator * add disappears test case for APIGW Resource * add disappears test case for APIGW Rest API * add disappears test case for APIGW Stage * add disappears test case for APIGW Usage Plan Key * add disappears test case for APIGW Usage Plan * add disappears test case for APIGW VPC Link * fix * fix lint docs/resource/aws_codebuild_project: Add SECRETS_MANAGER to the CodeBuild environment_variable type (#14200) Updates alexa example Updates api-gateway-websocket-chat-app example Updates asg example Updates cloudhsm example Updates cloudwatch-events kinesis and sns examples Updates cognito-user-pool example Updates count example Updates dx-gateway-cross-account-vgw-association example Updates ecs-alb example Updates eip example Updates eks-getting-started example Updates elasticsearch-domain example Updates elb example Updates lambda example Updates lambda-file-system example Updates networking example Updates rds example Updates s3-api-gateway-integration example Updates s3-cross-account-access Updates sagemaker example Updates transit-gateway-cross-account-peering-attachment example Updates transit-gateway-cross-account-vpc-attachment example Updates two-tier example Updates workspaces example Updates example action workflow to validate only with Terraform 0.12. Adds error for testing Restore `terraform validate` output Only check for warnings if there are no errors Fixes bash conditional Wraps jq result in quotes to force it into a string to avoid "unary operator expected" error Tightens warning check Updates warning equality Simplify warning check since it will exit on syntax errors Resetting warning test to debug it Add back terraform validate -json Adds back jq Echoes warning count Step-by-step Baby steps One step back Again Try anything Drops checks for warnings Removes error added for testing Got it! resource/aws_ssm_maintenance_window_task: Remove deprecated logging_info and task_parameters configuration blocks (#14311) Reference: https://github.com/terraform-providers/terraform-provider-aws/pull/7823 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13398 Output from acceptance testing: ``` --- PASS: TestAccAWSSSMMaintenanceWindowTask_emptyNotificationConfig (13.56s) --- PASS: TestAccAWSSSMMaintenanceWindowTask_TaskInvocationStepFunctionParameters (14.66s) --- PASS: TestAccAWSSSMMaintenanceWindowTask_updateForcesNewResource (22.46s) --- PASS: TestAccAWSSSMMaintenanceWindowTask_basic (22.75s) --- PASS: TestAccAWSSSMMaintenanceWindowTask_TaskInvocationLambdaParameters (36.30s) --- PASS: TestAccAWSSSMMaintenanceWindowTask_TaskInvocationAutomationParameters (36.56s) --- PASS: TestAccAWSSSMMaintenanceWindowTask_TaskInvocationRunCommandParameters (39.53s) ``` Update CHANGELOG for #14311 resource/aws_lb_listener_rule: Remove deprecated condition configuration block field and values arguments (#14309) Reference: https://github.com/terraform-providers/terraform-provider-aws/pull/8268 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13398 Already documented in the version 3 upgrade guide. Output from acceptance testing: ``` --- PASS: TestAccAWSLBListenerRule_Action_Order (242.39s) --- PASS: TestAccAWSLBListenerRule_Action_Order_Recreates (172.01s) --- PASS: TestAccAWSLBListenerRule_BackwardsCompatibility (192.52s) --- PASS: TestAccAWSLBListenerRule_basic (205.77s) --- PASS: TestAccAWSLBListenerRule_changeListenerRuleArnForcesNew (234.49s) --- PASS: TestAccAWSLBListenerRule_cognito (190.75s) --- PASS: TestAccAWSLBListenerRule_conditionAttributesCount (10.86s) --- PASS: TestAccAWSLBListenerRule_conditionHostHeader (227.40s) --- PASS: TestAccAWSLBListenerRule_conditionHttpHeader (194.36s) --- PASS: TestAccAWSLBListenerRule_conditionHttpHeader_invalid (1.43s) --- PASS: TestAccAWSLBListenerRule_conditionHttpRequestMethod (195.55s) --- PASS: TestAccAWSLBListenerRule_conditionMultiple (269.78s) --- PASS: TestAccAWSLBListenerRule_conditionPathPattern (199.17s) --- PASS: TestAccAWSLBListenerRule_conditionQueryString (195.57s) --- PASS: TestAccAWSLBListenerRule_conditionSourceIp (186.73s) --- PASS: TestAccAWSLBListenerRule_conditionUpdateMixed (274.24s) --- PASS: TestAccAWSLBListenerRule_conditionUpdateMultiple (267.11s) --- PASS: TestAccAWSLBListenerRule_fixedResponse (213.36s) --- PASS: TestAccAWSLBListenerRule_forwardWeighted (213.62s) --- PASS: TestAccAWSLBListenerRule_oidc (206.04s) --- PASS: TestAccAWSLBListenerRule_priority (377.75s) --- PASS: TestAccAWSLBListenerRule_redirect (248.43s) --- PASS: TestAccAWSLBListenerRule_updateFixedResponse (189.01s) --- PASS: TestAccAWSLBListenerRule_updateRulePriority (206.44s) ``` Update CHANGELOG for #14309 resource/aws_cognito_user_pool: Remove deprecated admin_create_user_config.unused_account_validity_days argument (#14294) Reference: https://github.com/terraform-providers/terraform-provider-aws/pull/10890 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13398 Output from acceptance testing: ``` --- PASS: TestAccAWSCognitoUserPool_basic (16.93s) --- PASS: TestAccAWSCognitoUserPool_MfaConfiguration_SmsConfiguration (47.75s) --- PASS: TestAccAWSCognitoUserPool_MfaConfiguration_SmsConfigurationAndSoftwareTokenMfaConfiguration (50.45s) --- PASS: TestAccAWSCognitoUserPool_MfaConfiguration_SmsConfigurationToSoftwareTokenMfaConfiguration (46.37s) --- PASS: TestAccAWSCognitoUserPool_MfaConfiguration_SoftwareTokenMfaConfiguration (41.83s) --- PASS: TestAccAWSCognitoUserPool_MfaConfiguration_SoftwareTokenMfaConfigurationToSmsConfiguration (35.22s) --- PASS: TestAccAWSCognitoUserPool_SmsAuthenticationMessage (36.72s) --- PASS: TestAccAWSCognitoUserPool_SmsConfiguration (45.69s) --- PASS: TestAccAWSCognitoUserPool_SmsConfiguration_ExternalId (43.87s) --- PASS: TestAccAWSCognitoUserPool_SmsConfiguration_SnsCallerArn (41.27s) --- PASS: TestAccAWSCognitoUserPool_SmsVerificationMessage (21.39s) --- PASS: TestAccAWSCognitoUserPool_update (38.77s) --- PASS: TestAccAWSCognitoUserPool_withAdminCreateUserConfiguration (26.14s) --- PASS: TestAccAWSCognitoUserPool_withAdminCreateUserConfigurationAndPasswordPolicy (13.70s) --- PASS: TestAccAWSCognitoUserPool_withAdvancedSecurityMode (32.33s) --- PASS: TestAccAWSCognitoUserPool_withAliasAttributes (23.59s) --- PASS: TestAccAWSCognitoUserPool_withDeviceConfiguration (21.89s) --- PASS: TestAccAWSCognitoUserPool_withEmailVerificationMessage (21.15s) --- PASS: TestAccAWSCognitoUserPool_withLambdaConfig (46.71s) --- PASS: TestAccAWSCognitoUserPool_withPasswordPolicy (36.75s) --- PASS: TestAccAWSCognitoUserPool_withSchemaAttributes (22.83s) --- PASS: TestAccAWSCognitoUserPool_withTags (33.77s) --- PASS: TestAccAWSCognitoUserPool_withUsernameConfiguration (28.12s) --- PASS: TestAccAWSCognitoUserPool_withVerificationMessageTemplate (21.48s) ``` Update CHANGELOG for #14294 tests/provider: Ensure awsproviderlint source is dependency and lint checked (#14131) * tests/provider: Ensure awsproviderlint source is dependency and lint checked Reference: https://github.com/terraform-providers/terraform-provider-aws/pull/14129 * provider: Add awsproviderlint to make fmt target provider: Initial snapshot build workflow (#14140) Using GitHub Actions artifacts, sets up daily snapshot builds of master and allows other snapshot builds. resource/aws_iam_access_key: Remove deprecated ses_smtp_password attribute (#14299) Reference: https://github.com/terraform-providers/terraform-provider-aws/pull/11144 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13398 Output from acceptance testing: ``` --- PASS: TestAccAWSAccessKey_basic (5.87s) --- PASS: TestAccAWSAccessKey_encrypted (5.97s) --- PASS: TestAccAWSAccessKey_inactive (9.72s) ``` Update CHANGELOG for #14299 provider: Remove deprecated kinesis_analytics and r53 custom endpoint arguments (#14238) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13398 Output from acceptance testing: ``` --- PASS: TestAccAWSProvider_Region_AwsCommercial (3.64s) --- PASS: TestAccAWSProvider_Region_AwsChina (3.64s) --- PASS: TestAccAWSProvider_Region_AwsGovCloudUs (3.65s) --- PASS: TestAccAWSProvider_IgnoreTags_KeyPrefixes_Multiple (4.00s) --- PASS: TestAccAWSProvider_IgnoreTags_Keys_None (4.00s) --- PASS: TestAccAWSProvider_IgnoreTags_Keys_Multiple (4.01s) --- PASS: TestAccAWSProvider_IgnoreTags_Keys_One (4.01s) --- PASS: TestAccAWSProvider_IgnoreTags_KeyPrefixes_None (4.01s) --- PASS: TestAccAWSProvider_IgnoreTags_KeyPrefixes_One (4.02s) --- PASS: TestAccAWSProvider_IgnoreTags_EmptyConfigurationBlock (4.01s) --- PASS: TestAccAWSProvider_Endpoints (4.08s) --- PASS: TestAccAWSProvider_AssumeRole_Empty (7.80s) ``` Update CHANGELOG for #14238 resource/aws_glue_job: Remove deprecated allocated_capacity argument (#14296) Reference: https://github.com/terraform-providers/terraform-provider-aws/pull/7340 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13398 Output from acceptance testing: ``` --- PASS: TestAccAWSGlueJob_basic (14.45s) --- PASS: TestAccAWSGlueJob_Description (21.70s) --- PASS: TestAccAWSGlueJob_GlueVersion (21.74s) --- PASS: TestAccAWSGlueJob_MaxRetries (21.92s) --- PASS: TestAccAWSGlueJob_Command (21.95s) --- PASS: TestAccAWSGlueJob_DefaultArguments (22.08s) --- PASS: TestAccAWSGlueJob_NotificationProperty (22.10s) --- PASS: TestAccAWSGlueJob_Timeout (22.13s) --- PASS: TestAccAWSGlueJob_ExecutionProperty (22.43s) --- PASS: TestAccAWSGlueJob_MaxCapacity (22.43s) --- PASS: TestAccAWSGlueJob_SecurityConfiguration (22.48s) --- PASS: TestAccAWSGlueJob_WorkerType (29.22s) --- PASS: TestAccAWSGlueJob_Tags (29.29s) --- PASS: TestAccAWSGlueJob_PythonShell (30.12s) ``` Update CHANGELOG for #14296 resource/aws_iam_instance_profile: Remove deprecated roles argument (#14303) Reference: https://github.com/hashicorp/terraform/pull/13130 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13398 Output from acceptance testing: ``` --- PASS: TestAccAWSIAMInstanceProfile_withoutRole (6.44s) --- PASS: TestAccAWSIAMInstanceProfile_basic (6.92s) --- PASS: TestAccAWSIAMInstanceProfile_namePrefix (6.94s) --- PASS: TestAccAWSAutoScalingGroup_LaunchTemplate_IAMInstanceProfile (53.25s) --- PASS: TestAccAWSAppautoScalingTarget_emrCluster (790.81s) --- PASS: TestAccAWSBeanstalkEnv_tier (518.46s) --- PASS: TestAccAWSIAMRole_testNameChange (12.80s) --- PASS: TestAccAWSInstance_instanceProfileChange (204.32s) --- PASS: TestAccAWSInstance_withIamInstanceProfile (115.26s) --- PASS: TestAccAWSLaunchConfiguration_withIAMProfile (21.61s) ``` Update CHANGELOG for #14303 Remove hardcoded AMIs and AZs resource/aws_sns_topic_subscription: Use paginated ListSubscriptionsByTopic and return immediately on errors (#14262) * tests/resource/aws_sns_topic_subscription: Fix recurring and unrelated test configuration error Previously: ``` --- FAIL: TestAccAWSSNSTopicSubscription_autoConfirmingSecuredEndpoint (63.28s) testing.go:684: Step 0 error: After applying this step, the plan was not empty: DIFF: UPDATE: aws_api_gateway_authorizer.test ... authorizer_result_ttl_in_seconds: "300" => "0" ``` Output from acceptance testing: ``` --- PASS: TestAccAWSSNSTopicSubscription_autoConfirmingSecuredEndpoint (91.18s) ``` * resource/aws_sns_topic_subscription: Use paginated ListSubscriptionsByTopic and return immediately on errors Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13409 Output from acceptance testing: ``` --- PASS: TestAccAWSSNSTopicSubscription_basic (13.47s) --- PASS: TestAccAWSSNSTopicSubscription_rawMessageDelivery (27.13s) --- PASS: TestAccAWSSNSTopicSubscription_filterPolicy (28.12s) --- PASS: TestAccAWSSNSTopicSubscription_deliveryPolicy (28.38s) --- PASS: TestAccAWSSNSTopicSubscription_autoConfirmingEndpoint (48.31s) --- PASS: TestAccAWSSNSTopicSubscription_autoConfirmingSecuredEndpoint (91.18s) ``` Update CHANGELOG for #14262 service/directconnect: vpn_gateway_id Argument Removals and Increase aws_dx_gateway_association Default Timeouts (#14144) * resource/aws_dx_gateway_association: Increase default create/update/delete timeouts to 30 minutes Previously, we were seeing consistent failures across many of acceptance tests: ``` TestAccAwsDxGatewayAssociation_allowedPrefixesVpnGatewaySingleAccount: testing.go:684: Step 1 error: errors during apply: Error: error waiting for Direct Connect gateway association (ga-a59d30b3-e6de-435e-bb17-cd7ed23f400evgw-06bccd6488d2b8d87) to become available: timeout while waiting for state to become 'associated' (last state: 'updating', timeout: 10m0s) TestAccAwsDxGatewayAssociation_allowedPrefixesVpnGatewayCrossAccount: testing.go:684: Step 1 error: errors during apply: Error: error waiting for Direct Connect gateway association (ga-a8b1b976-c0a1-4b64-8560-9d9cc45d11a3vgw-0a2e52679acf9c250) to become available: timeout while waiting for state to become 'associated' (last state: 'updating', timeout: 10m0s) --- FAIL: TestAccAwsDxGatewayAssociation_basicTransitGatewaySingleAccount (989.81s) testing.go:684: Step 0 error: errors during apply: Error: error waiting for Direct Connect gateway association (ga-48d0e3d3-e131-443d-9693-e64eff519baatgw-0a2a0ea77f65ed202) to become available: timeout while waiting for state to become 'associated' (last state: 'associating', timeout: 15m0s) --- FAIL: TestAccAwsDxGatewayAssociation_basicTransitGatewayCrossAccount (991.80s) testing.go:684: Step 0 error: errors during apply: Error: error waiting for Direct Connect gateway association (ga-9f9c1ed2-97b6-41c5-8018-0724f6162b59tgw-06f7ce56df96282d7) to become available: timeout while waiting for state to become 'associated' (last state: 'associating', timeout: 15m0s) --- FAIL: TestAccAwsDxGatewayAssociation_basicVpnGatewaySingleAccount (1816.92s) testing.go:684: Step 0 error: errors during apply: Error: error waiting for Direct Connect gateway association (ga-76c9d0f4-b0aa-4b1b-96d9-10ce8c3ca025vgw-0c47a2c63baf7d4d8) to become available: timeout while waiting for state to become 'associated' (last state: 'associating', timeout: 15m0s) testing.go:745: Error destroying resource! WARNING: Dangling resources may exist. The full state and error is shown below. Error: errors during apply: error waiting for Direct Connect gateway association (ga-76c9d0f4-b0aa-4b1b-96d9-10ce8c3ca025vgw-0c47a2c63baf7d4d8) to be deleted: timeout while waiting for state to become 'disassociated, deleted' (last state: 'disassociating', timeout: 15m0s) --- FAIL: TestAccAwsDxGatewayAssociation_allowedPrefixesVpnGatewaySingleAccount (1816.89s) testing.go:684: Step 0 error: errors during apply: Error: error waiting for Direct Connect gateway association (ga-12a5c1e8-322e-4bc1-8a5a-f4b778a00db3vgw-09c811d121256131b) to become available: timeout while waiting for state to become 'associated' (last state: 'associating', timeout: 15m0s) testing.go:745: Error destroying resource! WARNING: Dangling resources may exist. The full state and error is shown below. Error: errors during apply: error waiting for Direct Connect gateway association (ga-12a5c1e8-322e-4bc1-8a5a-f4b778a00db3vgw-09c811d121256131b) to be deleted: timeout while waiting for state to become 'disassociated, deleted' (last state: 'disassociating', timeout: 15m0s) --- FAIL: TestAccAwsDxGatewayAssociation_allowedPrefixesVpnGatewayCrossAccount (1819.25s) testing.go:684: Step 0 error: errors during apply: Error: error waiting for Direct Connect gateway association (ga-ccf678f2-5d51-441e-86c5-308c731f26abvgw-063e75f539bc3719c) to become available: timeout while waiting for state to become 'associated' (last state: 'associating', timeout: 15m0s) testing.go:745: Error destroying resource! WARNING: Dangling resources may exist. The full state and error is shown below. Error: errors during apply: error waiting for Direct Connect gateway association (ga-ccf678f2-5d51-441e-86c5-308c731f26abvgw-063e75f539bc3719c) to be deleted: timeout while waiting for state to become 'disassociated, deleted' (last state: 'disassociating', timeout: 15m0s) --- FAIL: TestAccAwsDxGatewayAssociation_multiVpnGatewaysSingleAccount (2487.01s) testing.go:684: Step 0 error: errors during apply: Error: error waiting for Direct Connect gateway association (ga-5d93ccd0-8344-4ee6-95f8-58af27e01301vgw-054e2b0e7ecf45c8d) to become available: timeout while waiting for state to become 'associated' (last state: 'associating', timeout: 15m0s) Error: error waiting for Direct Connect gateway association (ga-5d93ccd0-8344-4ee6-95f8-58af27e01301vgw-057b39dbec7338ec1) to become available: timeout while waiting for state to become 'associated' (last state: 'associating', timeout: 15m0s) testing.go:745: Error destroying resource! WARNING: Dangling resources may exist. The full state and error is shown below. Error: errors during apply: error waiting for Direct Connect gateway association (ga-5d93ccd0-8344-4ee6-95f8-58af27e01301vgw-057b39dbec7338ec1) to be deleted: timeout while waiting for state to become 'disassociated, deleted' (last state: 'disassociating', timeout: 15m0s) --- FAIL: TestAccAwsDxGatewayAssociation_basicVpnGatewayCrossAccount (2529.42s) testing.go:684: Step 0 error: errors during apply: Error: error waiting for Direct Connect gateway association (ga-ad8143a9-657e-4ed2-9ebb-a78dd2bee2c1vgw-0d552249edec48941) to become available: timeout while waiting for state to become 'associated' (last state: 'associating', timeout: 15m0s) testing.go:745: Error destroying resource! WARNING: Dangling resources may exist. The full state and error is shown below. Error: errors during apply: Error waiting for VPN Gateway "vgw-0d552249edec48941" to detach from VPC "vpc-0cbba5ddf6a4ec7ba": timeout while waiting for state to become 'detached' (last state: 'detaching', timeout: 15m0s) --- FAIL: TestAccAwsDxGatewayAssociation_deprecatedSingleAccount (2551.41s) testing.go:684: Step 0 error: errors during apply: Error: error waiting for Direct Connect gateway association (ga-c1c37095-ab8d-4dcd-9f97-b369face1ad4vgw-0576f5ab3096ace51) to become available: timeout while waiting for state to become 'associated' (last state: 'associating', timeout: 15m0s) ``` * service/directconnect: Remove vpn_gateway_id arguments Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13398 Changes: ``` * resource/aws_dx_gateway_association: Remove `vpn_gateway_id` argument * resource/aws_dx_gateway_association_proposal: Remove `vpn_gateway_id` argument ``` Output from acceptance testing: ``` --- PASS: TestAccAwsDxGatewayAssociation_basicTransitGatewaySingleAccount (2063.56s) --- PASS: TestAccAwsDxGatewayAssociation_basicTransitGatewayCrossAccount (2556.75s) --- PASS: TestAccAwsDxGatewayAssociation_multiVpnGatewaysSingleAccount (2668.06s) --- PASS: TestAccAwsDxGatewayAssociation_basicVpnGatewaySingleAccount (2674.09s) --- PASS: TestAccAwsDxGatewayAssociation_basicVpnGatewayCrossAccount (2677.20s) --- PASS: TestAccAwsDxGatewayAssociation_allowedPrefixesVpnGatewaySingleAccount (3612.36s) --- PASS: TestAccAwsDxGatewayAssociation_allowedPrefixesVpnGatewayCrossAccount (3856.32s) --- PASS: TestAccAwsDxGatewayAssociationProposal_basicVpnGateway (88.64s) --- PASS: TestAccAwsDxGatewayAssociationProposal_disappears (96.50s) --- PASS: TestAccAwsDxGatewayAssociationProposal_AllowedPrefixes (121.18s) --- PASS: TestAccAwsDxGatewayAssociationProposal_basicTransitGateway (182.42s) ``` * tests/resource/aws_dx_gateway_association: Ensure v0 state upgrade is still covered by acceptance testing Output from acceptance testing: ``` --- PASS: TestAccAwsDxGatewayAssociation_V0StateUpgrade (2605.48s) ``` Update CHANGELOG for #14144 docs/resource/aws_security_group: Update `cidr_blocks` value to list (#14329) add support for zero ttl add validation for `authorizer_uri`, `authorizer_credentials` changes for %w remove deprecated func use set len func revert validation for `authorizer_uri` refactor tests refactor tests Update CHANGELOG for #12643 resource/aws_appautoscaling_target: Remove DeregisterScalableTarget retries on all errors and add disappears test (#14259) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13409 Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13826 Output from acceptance testing: ``` --- PASS: TestAccAWSAppautoScalingTarget_multipleTargets (20.68s) --- PASS: TestAccAWSAppautoScalingTarget_optionalRoleArn (25.17s) --- PASS: TestAccAWSAppautoScalingTarget_basic (43.13s) --- PASS: TestAccAWSAppautoScalingTarget_spotFleetRequest (57.42s) --- PASS: TestAccAWSAppautoScalingTarget_disappears (71.79s) --- PASS: TestAccAWSAppautoScalingTarget_emrCluster (840.33s) --- PASS: TestAccAWSAppautoScalingPolicy_multiplePoliciesSameName (24.97s) --- PASS: TestAccAWSAppautoScalingPolicy_dynamodb_table (26.58s) --- PASS: TestAccAWSAppautoScalingPolicy_multiplePoliciesSameResource (28.13s) --- PASS: TestAccAWSAppautoScalingPolicy_dynamodb_index (37.07s) --- PASS: TestAccAWSAppautoScalingPolicy_spotFleetRequest (71.64s) --- PASS: TestAccAWSAppautoScalingPolicy_disappears (75.45s) --- PASS: TestAccAWSAppautoScalingPolicy_basic (77.30s) --- PASS: TestAccAWSAppautoScalingPolicy_scaleOutAndIn (79.17s) --- PASS: TestAccAWSAppautoScalingPolicy_ResourceId_ForceNew (83.72s) ``` Update CHANGELOG for #14259 update statefuncs to use global method update statefuncs to use global method Update provider's S3 bucket lookup to use GetBucketRegion utility (#14221) * Update provider's S3 bucket lookup to use GetBucketRegion utility Replaces the usage of S3's GetBucketLocation with the aws-sdk-go's GetBucketRegion utility. This utility can discover the bucket's region without authentication, and can be configured to be compatible with FIPS endpoints. Fixes https://github.com/terraform-providers/terraform-provider-aws/issues/14217 Related to https://github.com/aws/aws-sdk-go/issues/3115 * Add AWS SDK for Go s3manager dependency Adds a dependency on the AWS SDK for Go's `s3manager`, and `s3iface` packages. These packages make the s3manager packages's GetBucketRegion utility available for discovering a S3 bucket's locations. These packages are used by PR #14221. Update CHANGELOG for #14221 and other minor formatting fixes refactor trimTrailingPeriod method --- aws/data_source_aws_route53_resolver_rule.go | 4 +- aws/data_source_aws_route53_zone.go | 32 +++----- aws/data_source_aws_route53_zone_test.go | 2 +- aws/diff_suppress_funcs.go | 8 -- aws/diff_suppress_funcs_test.go | 56 ------------- aws/resource_aws_acm_certificate.go | 34 ++++---- aws/resource_aws_acm_certificate_test.go | 30 +++---- aws/resource_aws_route53_record.go | 81 +++++++++---------- aws/resource_aws_route53_record_test.go | 4 +- aws/resource_aws_route53_resolver_rule.go | 14 ++-- ...resource_aws_route53_resolver_rule_test.go | 22 ++--- aws/resource_aws_route53_zone.go | 32 ++++++-- aws/resource_aws_route53_zone_test.go | 48 +++++++---- aws/resource_aws_ses_domain_identity.go | 12 +-- ...ce_aws_ses_domain_identity_verification.go | 13 ++- website/docs/guides/version-3-upgrade.html.md | 34 ++++++++ 16 files changed, 214 insertions(+), 212 deletions(-) diff --git a/aws/data_source_aws_route53_resolver_rule.go b/aws/data_source_aws_route53_resolver_rule.go index 943a1d9a07f..e491830ae55 100644 --- a/aws/data_source_aws_route53_resolver_rule.go +++ b/aws/data_source_aws_route53_resolver_rule.go @@ -122,7 +122,9 @@ func dataSourceAwsRoute53ResolverRuleRead(d *schema.ResourceData, meta interface d.SetId(aws.StringValue(rule.Id)) arn := *rule.Arn d.Set("arn", arn) - d.Set("domain_name", rule.DomainName) + // To be consistent with other AWS services that do not accept a trailing period, + // we remove the suffix from the Domain Name returned from the API + d.Set("domain_name", trimTrailingPeriod(aws.StringValue(rule.DomainName))) d.Set("name", rule.Name) d.Set("owner_id", rule.OwnerId) d.Set("resolver_endpoint_id", rule.ResolverEndpointId) diff --git a/aws/data_source_aws_route53_zone.go b/aws/data_source_aws_route53_zone.go index 0feff3f9e76..3ad11ae3405 100644 --- a/aws/data_source_aws_route53_zone.go +++ b/aws/data_source_aws_route53_zone.go @@ -3,7 +3,6 @@ package aws import ( "fmt" "log" - "strings" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/route53" @@ -72,7 +71,7 @@ func dataSourceAwsRoute53ZoneRead(d *schema.ResourceData, meta interface{}) erro ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig name, nameExists := d.GetOk("name") - name = hostedZoneName(name.(string)) + name = name.(string) id, idExists := d.GetOk("zone_id") vpcId, vpcIdExists := d.GetOk("vpc_id") tags := keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws() @@ -101,12 +100,12 @@ func dataSourceAwsRoute53ZoneRead(d *schema.ResourceData, meta interface{}) erro return fmt.Errorf("Error finding Route 53 Hosted Zone: %v", err) } for _, hostedZone := range resp.HostedZones { - hostedZoneId := cleanZoneID(*hostedZone.Id) + hostedZoneId := cleanZoneID(aws.StringValue(hostedZone.Id)) if idExists && hostedZoneId == id.(string) { hostedZoneFound = hostedZone break // we check if the name is the same as requested and if private zone field is the same as requested or if there is a vpc_id - } else if *hostedZone.Name == name && (*hostedZone.Config.PrivateZone == d.Get("private_zone").(bool) || (*hostedZone.Config.PrivateZone && vpcIdExists)) { + } else if (trimTrailingPeriod(aws.StringValue(hostedZone.Name)) == trimTrailingPeriod(name)) && (aws.BoolValue(hostedZone.Config.PrivateZone) == d.Get("private_zone").(bool) || (aws.BoolValue(hostedZone.Config.PrivateZone) && vpcIdExists)) { matchingVPC := false if vpcIdExists { reqHostedZone := &route53.GetHostedZoneInput{} @@ -118,7 +117,7 @@ func dataSourceAwsRoute53ZoneRead(d *schema.ResourceData, meta interface{}) erro } // we go through all VPCs for _, vpc := range respHostedZone.VPCs { - if *vpc.VPCId == vpcId.(string) { + if aws.StringValue(vpc.VPCId) == vpcId.(string) { matchingVPC = true break } @@ -132,7 +131,7 @@ func dataSourceAwsRoute53ZoneRead(d *schema.ResourceData, meta interface{}) erro listTags, err := keyvaluetags.Route53ListTags(conn, hostedZoneId, route53.TagResourceTypeHostedzone) if err != nil { - return fmt.Errorf("Error finding Route 53 Hosted Zone: %v", err) + return fmt.Errorf("Error finding Route 53 Hosted Zone: %w", err) } matchingTags = listTags.ContainsAll(tags) } @@ -156,10 +155,12 @@ func dataSourceAwsRoute53ZoneRead(d *schema.ResourceData, meta interface{}) erro return fmt.Errorf("no matching Route53Zone found") } - idHostedZone := cleanZoneID(*hostedZoneFound.Id) + idHostedZone := cleanZoneID(aws.StringValue(hostedZoneFound.Id)) d.SetId(idHostedZone) d.Set("zone_id", idHostedZone) - d.Set("name", hostedZoneFound.Name) + // To be consistent with other AWS services (e.g. ACM) that do not accept a trailing period, + // we remove the suffix from the Hosted Zone Name returned from the API + d.Set("name", trimTrailingPeriod(aws.StringValue(hostedZoneFound.Name))) d.Set("comment", hostedZoneFound.Config.Comment) d.Set("private_zone", hostedZoneFound.Config.PrivateZone) d.Set("caller_reference", hostedZoneFound.CallerReference) @@ -173,7 +174,9 @@ func dataSourceAwsRoute53ZoneRead(d *schema.ResourceData, meta interface{}) erro if err != nil { return fmt.Errorf("Error finding Route 53 Hosted Zone: %v", err) } - d.Set("name_servers", nameServers) + if err := d.Set("name_servers", nameServers); err != nil { + return fmt.Errorf("error setting name_servers: %w", err) + } tags, err = keyvaluetags.Route53ListTags(conn, idHostedZone, route53.TagResourceTypeHostedzone) @@ -188,15 +191,6 @@ func dataSourceAwsRoute53ZoneRead(d *schema.ResourceData, meta interface{}) erro return nil } -// used to manage trailing . -func hostedZoneName(name string) string { - if strings.HasSuffix(name, ".") { - return name - } - - return name + "." -} - // used to retrieve name servers func hostedZoneNameServers(id string, conn *route53.Route53) ([]string, error) { req := &route53.GetHostedZoneInput{} @@ -214,7 +208,7 @@ func hostedZoneNameServers(id string, conn *route53.Route53) ([]string, error) { servers := []string{} for _, server := range resp.DelegationSet.NameServers { if server != nil { - servers = append(servers, *server) + servers = append(servers, aws.StringValue(server)) } } return servers, nil diff --git a/aws/data_source_aws_route53_zone_test.go b/aws/data_source_aws_route53_zone_test.go index 2cac4bfa7e7..4a5dad3feea 100644 --- a/aws/data_source_aws_route53_zone_test.go +++ b/aws/data_source_aws_route53_zone_test.go @@ -221,7 +221,7 @@ resource "aws_vpc" "test" { } resource "aws_service_discovery_private_dns_namespace" "test" { - name = "test.acc-sd-%[1]d." + name = "test.acc-sd-%[1]d" vpc = "${aws_vpc.test.id}" } diff --git a/aws/diff_suppress_funcs.go b/aws/diff_suppress_funcs.go index 7597f801308..35c7ee2c87b 100644 --- a/aws/diff_suppress_funcs.go +++ b/aws/diff_suppress_funcs.go @@ -115,14 +115,6 @@ func suppressCloudFormationTemplateBodyDiffs(k, old, new string, d *schema.Resou return normalizedOld == normalizedNew } -func suppressRoute53ZoneNameWithTrailingDot(k, old, new string, d *schema.ResourceData) bool { - // "." is different from "". - if old == "." || new == "." { - return old == new - } - return strings.TrimSuffix(old, ".") == strings.TrimSuffix(new, ".") -} - // suppressEqualCIDRBlockDiffs provides custom difference suppression for CIDR blocks // that have different string values but represent the same CIDR. func suppressEqualCIDRBlockDiffs(k, old, new string, d *schema.ResourceData) bool { diff --git a/aws/diff_suppress_funcs_test.go b/aws/diff_suppress_funcs_test.go index 33e74881e8f..582dec4c8ea 100644 --- a/aws/diff_suppress_funcs_test.go +++ b/aws/diff_suppress_funcs_test.go @@ -264,59 +264,3 @@ Outputs: } } } - -func TestSuppressRoute53ZoneNameWithTrailingDot(t *testing.T) { - testCases := []struct { - old string - new string - equivalent bool - }{ - { - old: "example.com", - new: "example.com", - equivalent: true, - }, - { - old: "example.com.", - new: "example.com.", - equivalent: true, - }, - { - old: "example.com.", - new: "example.com", - equivalent: true, - }, - { - old: "example.com", - new: "example.com.", - equivalent: true, - }, - { - old: ".", - new: "", - equivalent: false, - }, - { - old: "", - new: ".", - equivalent: false, - }, - { - old: ".", - new: ".", - equivalent: true, - }, - } - - for i, tc := range testCases { - value := suppressRoute53ZoneNameWithTrailingDot("test_property", tc.old, tc.new, nil) - - if tc.equivalent && !value { - t.Fatalf("expected test case %d to be equivalent", i) - } - - if !tc.equivalent && value { - t.Fatalf("expected test case %d to not be equivalent", i) - } - } -} diff --git a/aws/resource_aws_acm_certificate.go b/aws/resource_aws_acm_certificate.go index 897eb8c3419..17535323b06 100644 --- a/aws/resource_aws_acm_certificate.go +++ b/aws/resource_aws_acm_certificate.go @@ -57,16 +57,15 @@ func resourceAwsAcmCertificate() *schema.Resource { ForceNew: true, }, "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 Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, ConflictsWith: []string{"private_key", "certificate_body", "certificate_chain"}, - StateFunc: func(v interface{}) string { - // AWS Provider 1.42.0+ aws_route53_zone references may contain a - // trailing period, which generates an ACM API error - return strings.TrimSuffix(v.(string), ".") - }, + StateFunc: trimTrailingPeriod, }, "subject_alternative_names": { Type: schema.TypeSet, @@ -75,11 +74,10 @@ func resourceAwsAcmCertificate() *schema.Resource { ForceNew: true, Elem: &schema.Schema{ Type: schema.TypeString, - StateFunc: func(v interface{}) string { - // AWS Provider 1.42.0+ aws_route53_zone references may contain a - // trailing period, which generates an ACM API error - return strings.TrimSuffix(v.(string), ".") - }, + // 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, }, Set: schema.HashString, ConflictsWith: []string{"private_key", "certificate_body", "certificate_chain"}, @@ -227,7 +225,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(strings.TrimSuffix(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{})), } @@ -283,7 +281,9 @@ func resourceAwsAcmCertificateRead(d *schema.ResourceData, meta interface{}) err return resource.NonRetryableError(fmt.Errorf("Error describing certificate: %s", err)) } - d.Set("domain_name", resp.Certificate.DomainName) + // 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("arn", resp.Certificate.CertificateArn) d.Set("certificate_authority_arn", resp.Certificate.CertificateAuthorityArn) @@ -389,10 +389,12 @@ func convertValidationOptions(certificate *acm.CertificateDetail) ([]map[string] for _, o := range certificate.DomainValidationOptions { if o.ResourceRecord != nil { validationOption := map[string]interface{}{ - "domain_name": *o.DomainName, - "resource_record_name": *o.ResourceRecord.Name, - "resource_record_type": *o.ResourceRecord.Type, - "resource_record_value": *o.ResourceRecord.Value, + // 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)), + "resource_record_name": aws.StringValue(o.ResourceRecord.Name), + "resource_record_type": aws.StringValue(o.ResourceRecord.Type), + "resource_record_value": aws.StringValue(o.ResourceRecord.Value), } domainValidationResult = append(domainValidationResult, validationOption) } else if o.ValidationEmails != nil && len(o.ValidationEmails) > 0 { diff --git a/aws/resource_aws_acm_certificate_test.go b/aws/resource_aws_acm_certificate_test.go index 41e179cb421..fb17ce1fc80 100644 --- a/aws/resource_aws_acm_certificate_test.go +++ b/aws/resource_aws_acm_certificate_test.go @@ -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", domain), + resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(domain)), resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "0"), resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation), resource.TestCheckResourceAttr(resourceName, "subject_alternative_names.#", "0"), @@ -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", domain), + 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": domain, + "domain_name": trimTrailingPeriod(domain), "resource_record_type": "CNAME", }), resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation), @@ -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", rootDomain), + resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(rootDomain)), resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "1"), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ - "domain_name": rootDomain, + "domain_name": trimTrailingPeriod(rootDomain), "resource_record_type": "CNAME", }), resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation), @@ -263,10 +263,10 @@ func TestAccAWSAcmCertificate_root_TrailingPeriod(t *testing.T) { Config: testAccAcmCertificateConfig(domain, acm.ValidationMethodDns), Check: resource.ComposeTestCheckFunc( testAccMatchResourceAttrRegionalARN(resourceName, "arn", "acm", regexp.MustCompile(`certificate/.+`)), - resource.TestCheckResourceAttr(resourceName, "domain_name", strings.TrimSuffix(domain, ".")), + 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": strings.TrimSuffix(domain, "."), + "domain_name": trimTrailingPeriod(domain), "resource_record_type": "CNAME", }), resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation), @@ -298,7 +298,7 @@ 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", rootDomain), + resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(rootDomain)), resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "2"), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ "domain_name": rootDomain, @@ -310,7 +310,7 @@ func TestAccAWSAcmCertificate_rootAndWildcardSan(t *testing.T) { }), resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation), resource.TestCheckResourceAttr(resourceName, "subject_alternative_names.#", "1"), - tfawsresource.TestCheckTypeSetElemAttr(resourceName, "subject_alternative_names.*", wildcardDomain), + tfawsresource.TestCheckTypeSetElemAttr(resourceName, "subject_alternative_names.*", trimTrailingPeriod(wildcardDomain)), resource.TestCheckResourceAttr(resourceName, "validation_emails.#", "0"), resource.TestCheckResourceAttr(resourceName, "validation_method", acm.ValidationMethodDns), ), @@ -339,7 +339,7 @@ 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", domain), + resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(domain)), resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "2"), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ "domain_name": domain, @@ -351,7 +351,7 @@ func TestAccAWSAcmCertificate_san_single(t *testing.T) { }), resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation), resource.TestCheckResourceAttr(resourceName, "subject_alternative_names.#", "1"), - tfawsresource.TestCheckTypeSetElemAttr(resourceName, "subject_alternative_names.*", sanDomain), + tfawsresource.TestCheckTypeSetElemAttr(resourceName, "subject_alternative_names.*", trimTrailingPeriod(sanDomain)), resource.TestCheckResourceAttr(resourceName, "validation_emails.#", "0"), resource.TestCheckResourceAttr(resourceName, "validation_method", acm.ValidationMethodDns), ), @@ -381,7 +381,7 @@ 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", domain), + resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(domain)), resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "3"), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ "domain_name": domain, @@ -427,7 +427,7 @@ 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", domain), + resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(domain)), resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "2"), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ "domain_name": domain, @@ -467,7 +467,7 @@ 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", wildcardDomain), + resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(wildcardDomain)), resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "1"), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ "domain_name": wildcardDomain, @@ -502,7 +502,7 @@ 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", wildcardDomain), + resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(wildcardDomain)), resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "2"), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ "domain_name": rootDomain, diff --git a/aws/resource_aws_route53_record.go b/aws/resource_aws_route53_record.go index 6e172f280ce..1e270ad3731 100644 --- a/aws/resource_aws_route53_record.go +++ b/aws/resource_aws_route53_record.go @@ -16,7 +16,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/route53" ) @@ -42,7 +41,7 @@ func resourceAwsRoute53Record() *schema.Resource { Required: true, ForceNew: true, StateFunc: func(v interface{}) string { - value := strings.TrimSuffix(v.(string), ".") + value := trimTrailingPeriod(v) return strings.ToLower(value) }, }, @@ -273,7 +272,7 @@ func resourceAwsRoute53RecordUpdate(d *schema.ResourceData, meta interface{}) er } // Build the to be deleted record - en := expandRecordName(d.Get("name").(string), *zoneRecord.HostedZone.Name) + en := expandRecordName(d.Get("name").(string), aws.StringValue(zoneRecord.HostedZone.Name)) typeo, _ := d.GetChange("type") oldRec := &route53.ResourceRecordSet{ @@ -328,7 +327,7 @@ func resourceAwsRoute53RecordUpdate(d *schema.ResourceData, meta interface{}) er } // Build the to be created record - rec, err := resourceAwsRoute53RecordBuildSet(d, *zoneRecord.HostedZone.Name) + rec, err := resourceAwsRoute53RecordBuildSet(d, aws.StringValue(zoneRecord.HostedZone.Name)) if err != nil { return err } @@ -340,27 +339,27 @@ func resourceAwsRoute53RecordUpdate(d *schema.ResourceData, meta interface{}) er Comment: aws.String("Managed by Terraform"), Changes: []*route53.Change{ { - Action: aws.String("DELETE"), + Action: aws.String(route53.ChangeActionDelete), ResourceRecordSet: oldRec, }, { - Action: aws.String("CREATE"), + Action: aws.String(route53.ChangeActionCreate), ResourceRecordSet: rec, }, }, } input := &route53.ChangeResourceRecordSetsInput{ - HostedZoneId: aws.String(cleanZoneID(*zoneRecord.HostedZone.Id)), + HostedZoneId: aws.String(cleanZoneID(aws.StringValue(zoneRecord.HostedZone.Id))), ChangeBatch: changeBatch, } log.Printf("[DEBUG] Updating resource records for zone: %s, name: %s\n\n%s", - zone, *rec.Name, input) + zone, aws.StringValue(rec.Name), input) respRaw, err := changeRoute53RecordSet(conn, input) if err != nil { - return fmt.Errorf("[ERR]: Error building changeset: %s", err) + return fmt.Errorf("[ERR]: Error building changeset: %w", err) } changeInfo := respRaw.(*route53.ChangeResourceRecordSetsOutput).ChangeInfo @@ -377,7 +376,7 @@ func resourceAwsRoute53RecordUpdate(d *schema.ResourceData, meta interface{}) er d.SetId(strings.Join(vars, "_")) - err = waitForRoute53RecordSetToSync(conn, cleanChangeID(*changeInfo.Id)) + err = waitForRoute53RecordSetToSync(conn, cleanChangeID(aws.StringValue(changeInfo.Id))) if err != nil { return err } @@ -400,7 +399,7 @@ func resourceAwsRoute53RecordCreate(d *schema.ResourceData, meta interface{}) er } // Build the record - rec, err := resourceAwsRoute53RecordBuildSet(d, *zoneRecord.HostedZone.Name) + rec, err := resourceAwsRoute53RecordBuildSet(d, aws.StringValue(zoneRecord.HostedZone.Name)) if err != nil { return err } @@ -410,9 +409,9 @@ func resourceAwsRoute53RecordCreate(d *schema.ResourceData, meta interface{}) er // Else CREATE is used and fail if the same record exists var action string if d.Get("allow_overwrite").(bool) || !d.IsNewResource() { - action = "UPSERT" + action = route53.ChangeActionUpsert } else { - action = "CREATE" + action = route53.ChangeActionCreate } // Create the new records. We abuse StateChangeConf for this to @@ -429,16 +428,16 @@ func resourceAwsRoute53RecordCreate(d *schema.ResourceData, meta interface{}) er } req := &route53.ChangeResourceRecordSetsInput{ - HostedZoneId: aws.String(cleanZoneID(*zoneRecord.HostedZone.Id)), + HostedZoneId: aws.String(cleanZoneID(aws.StringValue(zoneRecord.HostedZone.Id))), ChangeBatch: changeBatch, } log.Printf("[DEBUG] Creating resource records for zone: %s, name: %s\n\n%s", - zone, *rec.Name, req) + zone, aws.StringValue(rec.Name), req) respRaw, err := changeRoute53RecordSet(conn, req) if err != nil { - return fmt.Errorf("[ERR]: Error building changeset: %s", err) + return fmt.Errorf("[ERR]: Error building changeset: %w", err) } changeInfo := respRaw.(*route53.ChangeResourceRecordSetsOutput).ChangeInfo @@ -455,7 +454,7 @@ func resourceAwsRoute53RecordCreate(d *schema.ResourceData, meta interface{}) er d.SetId(strings.Join(vars, "_")) - err = waitForRoute53RecordSetToSync(conn, cleanChangeID(*changeInfo.Id)) + err = waitForRoute53RecordSetToSync(conn, cleanChangeID(aws.StringValue(changeInfo.Id))) if err != nil { return err } @@ -469,7 +468,7 @@ func changeRoute53RecordSet(conn *route53.Route53, input *route53.ChangeResource err := resource.Retry(1*time.Minute, func() *resource.RetryError { var err error out, err = conn.ChangeResourceRecordSets(input) - if isAWSErr(err, "NoSuchHostedZone", "") { + if isAWSErr(err, route53.ErrCodeNoSuchHostedZone, "") { log.Print("[DEBUG] Hosted Zone not found, retrying...") return resource.RetryableError(err) } @@ -488,8 +487,8 @@ func changeRoute53RecordSet(conn *route53.Route53, input *route53.ChangeResource func waitForRoute53RecordSetToSync(conn *route53.Route53, requestId string) error { wait := resource.StateChangeConf{ Delay: 30 * time.Second, - Pending: []string{"PENDING"}, - Target: []string{"INSYNC"}, + Pending: []string{route53.ChangeStatusPending}, + Target: []string{route53.ChangeStatusInsync}, Timeout: 30 * time.Minute, MinTimeout: 5 * time.Second, Refresh: func() (result interface{}, state string, err error) { @@ -533,18 +532,18 @@ func resourceAwsRoute53RecordRead(d *schema.ResourceData, meta interface{}) erro } } - err = d.Set("records", flattenResourceRecords(record.ResourceRecords, *record.Type)) + err = d.Set("records", flattenResourceRecords(record.ResourceRecords, aws.StringValue(record.Type))) if err != nil { - return fmt.Errorf("Error setting records for: %s, error: %#v", d.Id(), err) + return fmt.Errorf("Error setting records for: %s, error: %w", d.Id(), err) } if alias := record.AliasTarget; alias != nil { - name := normalizeAwsAliasName(*alias.DNSName) + name := normalizeAwsAliasName(aws.StringValue(alias.DNSName)) d.Set("alias", []interface{}{ map[string]interface{}{ - "zone_id": *alias.HostedZoneId, + "zone_id": aws.StringValue(alias.HostedZoneId), "name": name, - "evaluate_target_health": *alias.EvaluateTargetHealth, + "evaluate_target_health": aws.BoolValue(alias.EvaluateTargetHealth), }, }) } @@ -556,7 +555,7 @@ func resourceAwsRoute53RecordRead(d *schema.ResourceData, meta interface{}) erro "type": aws.StringValue(record.Failover), }} if err := d.Set("failover_routing_policy", v); err != nil { - return fmt.Errorf("Error setting failover records for: %s, error: %#v", d.Id(), err) + return fmt.Errorf("Error setting failover records for: %s, error: %w", d.Id(), err) } } @@ -567,7 +566,7 @@ func resourceAwsRoute53RecordRead(d *schema.ResourceData, meta interface{}) erro "subdivision": aws.StringValue(record.GeoLocation.SubdivisionCode), }} if err := d.Set("geolocation_routing_policy", v); err != nil { - return fmt.Errorf("Error setting gelocation records for: %s, error: %#v", d.Id(), err) + return fmt.Errorf("Error setting gelocation records for: %s, error: %w", d.Id(), err) } } @@ -576,7 +575,7 @@ func resourceAwsRoute53RecordRead(d *schema.ResourceData, meta interface{}) erro "region": aws.StringValue(record.Region), }} if err := d.Set("latency_routing_policy", v); err != nil { - return fmt.Errorf("Error setting latency records for: %s, error: %#v", d.Id(), err) + return fmt.Errorf("Error setting latency records for: %s, error: %w", d.Id(), err) } } @@ -585,13 +584,13 @@ func resourceAwsRoute53RecordRead(d *schema.ResourceData, meta interface{}) erro "weight": aws.Int64Value((record.Weight)), }} if err := d.Set("weighted_routing_policy", v); err != nil { - return fmt.Errorf("Error setting weighted records for: %s, error: %#v", d.Id(), err) + return fmt.Errorf("Error setting weighted records for: %s, error: %w", d.Id(), err) } } if record.MultiValueAnswer != nil { if err := d.Set("multivalue_answer_routing_policy", record.MultiValueAnswer); err != nil { - return fmt.Errorf("Error setting multivalue answer records for: %s, error: %#v", d.Id(), err) + return fmt.Errorf("Error setting multivalue answer records for: %s, error: %w", d.Id(), err) } } @@ -624,9 +623,10 @@ func findRecord(d *schema.ResourceData, meta interface{}) (*route53.ResourceReco // get expanded name zoneRecord, err := conn.GetHostedZone(&route53.GetHostedZoneInput{Id: aws.String(zone)}) if err != nil { - if r53err, ok := err.(awserr.Error); ok && r53err.Code() == "NoSuchHostedZone" { + if isAWSErr(err, route53.ErrCodeNoSuchHostedZone, "") { return nil, r53NoHostedZoneFound } + return nil, err } @@ -640,13 +640,13 @@ func findRecord(d *schema.ResourceData, meta interface{}) (*route53.ResourceReco name = d.Get("name").(string) } - en := expandRecordName(name, *zoneRecord.HostedZone.Name) + en := expandRecordName(name, aws.StringValue(zoneRecord.HostedZone.Name)) log.Printf("[DEBUG] Expanded record name: %s", en) d.Set("fqdn", en) recordName := FQDN(strings.ToLower(en)) recordType := d.Get("type").(string) - recordSetIdentifier := d.Get("set_identifier") + recordSetIdentifier := d.Get("set_identifier").(string) // If this isn't a Weighted, Latency, Geo, or Failover resource with // a SetIdentifier we only need to look at the first record in the response since there can be @@ -678,7 +678,7 @@ func findRecord(d *schema.ResourceData, meta interface{}) (*route53.ResourceReco for _, recordSet := range resp.ResourceRecordSets { responseName := strings.ToLower(cleanRecordName(*recordSet.Name)) - responseType := strings.ToUpper(*recordSet.Type) + responseType := strings.ToUpper(aws.StringValue(recordSet.Type)) if recordName != responseName { continue @@ -686,7 +686,7 @@ func findRecord(d *schema.ResourceData, meta interface{}) (*route53.ResourceReco if recordType != responseType { continue } - if recordSet.SetIdentifier != nil && *recordSet.SetIdentifier != recordSetIdentifier { + if aws.StringValue(recordSet.SetIdentifier) != recordSetIdentifier { continue } @@ -735,7 +735,7 @@ func resourceAwsRoute53RecordDelete(d *schema.ResourceData, meta interface{}) er Comment: aws.String("Deleted by Terraform"), Changes: []*route53.Change{ { - Action: aws.String("DELETE"), + Action: aws.String(route53.ChangeActionDelete), ResourceRecordSet: rec, }, }, @@ -750,7 +750,7 @@ func resourceAwsRoute53RecordDelete(d *schema.ResourceData, meta interface{}) er respRaw, err := deleteRoute53RecordSet(conn, req) if err != nil { - return fmt.Errorf("[ERR]: Error building changeset: %s", err) + return fmt.Errorf("[ERR]: Error building changeset: %w", err) } changeInfo := respRaw.(*route53.ChangeResourceRecordSetsOutput).ChangeInfo @@ -759,13 +759,13 @@ func resourceAwsRoute53RecordDelete(d *schema.ResourceData, meta interface{}) er return nil } - err = waitForRoute53RecordSetToSync(conn, cleanChangeID(*changeInfo.Id)) + err = waitForRoute53RecordSetToSync(conn, cleanChangeID(aws.StringValue(changeInfo.Id))) return err } func deleteRoute53RecordSet(conn *route53.Route53, input *route53.ChangeResourceRecordSetsInput) (interface{}, error) { out, err := conn.ChangeResourceRecordSets(input) - if isAWSErr(err, "InvalidChangeBatch", "") { + if isAWSErr(err, route53.ErrCodeInvalidChangeBatch, "") { return out, nil } @@ -919,7 +919,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(strings.TrimSuffix(name, ".")) + rn := strings.ToLower(name) zone = strings.TrimSuffix(zone, ".") if !strings.HasSuffix(rn, zone) { if len(name) == 0 { @@ -974,6 +974,5 @@ func parseRecordId(id string) [4]string { } } } - recName = strings.TrimSuffix(recName, ".") return [4]string{recZone, recName, recType, recSet} } diff --git a/aws/resource_aws_route53_record_test.go b/aws/resource_aws_route53_record_test.go index e8b62ad56a0..52dfcec4caa 100644 --- a/aws/resource_aws_route53_record_test.go +++ b/aws/resource_aws_route53_record_test.go @@ -41,12 +41,10 @@ func TestExpandRecordName(t *testing.T) { Input, Output string }{ {"www", "www.nonexample.com"}, - {"www.", "www.nonexample.com"}, {"dev.www", "dev.www.nonexample.com"}, {"*", "*.nonexample.com"}, {"nonexample.com", "nonexample.com"}, {"test.nonexample.com", "test.nonexample.com"}, - {"test.nonexample.com.", "test.nonexample.com"}, } zone_name := "nonexample.com" @@ -83,7 +81,7 @@ func TestParseRecordId(t *testing.T) { Input, Zone, Name, Type, Set string }{ {"ABCDEF_test.notexample.com_A", "ABCDEF", "test.notexample.com", "A", ""}, - {"ABCDEF_test.notexample.com._A", "ABCDEF", "test.notexample.com", "A", ""}, + {"ABCDEF_test.notexample.com_A", "ABCDEF", "test.notexample.com", "A", ""}, {"ABCDEF_test.notexample.com_A_set1", "ABCDEF", "test.notexample.com", "A", "set1"}, {"ABCDEF__underscore.notexample.com_A", "ABCDEF", "_underscore.notexample.com", "A", ""}, {"ABCDEF__underscore.notexample.com_A_set1", "ABCDEF", "_underscore.notexample.com", "A", "set1"}, diff --git a/aws/resource_aws_route53_resolver_rule.go b/aws/resource_aws_route53_resolver_rule.go index 4730e044a7a..4fbcf598e1d 100644 --- a/aws/resource_aws_route53_resolver_rule.go +++ b/aws/resource_aws_route53_resolver_rule.go @@ -38,11 +38,11 @@ func resourceAwsRoute53ResolverRule() *schema.Resource { Schema: map[string]*schema.Schema{ "domain_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - DiffSuppressFunc: suppressRoute53ZoneNameWithTrailingDot, - ValidateFunc: validation.StringLenBetween(1, 256), + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 256), + StateFunc: trimTrailingPeriod, }, "rule_type": { @@ -163,7 +163,9 @@ func resourceAwsRoute53ResolverRuleRead(d *schema.ResourceData, meta interface{} rule := ruleRaw.(*route53resolver.ResolverRule) d.Set("arn", rule.Arn) - d.Set("domain_name", rule.DomainName) + // To be consistent with other AWS services that do not accept a trailing period, + // we remove the suffix from the Domain Name returned from the API + d.Set("domain_name", trimTrailingPeriod(aws.StringValue(rule.DomainName))) d.Set("name", rule.Name) d.Set("owner_id", rule.OwnerId) d.Set("resolver_endpoint_id", rule.ResolverEndpointId) diff --git a/aws/resource_aws_route53_resolver_rule_test.go b/aws/resource_aws_route53_resolver_rule_test.go index 4318e48b701..8bb487bc321 100644 --- a/aws/resource_aws_route53_resolver_rule_test.go +++ b/aws/resource_aws_route53_resolver_rule_test.go @@ -95,7 +95,7 @@ func TestAccAwsRoute53ResolverRule_basic(t *testing.T) { Config: testAccRoute53ResolverRuleConfig_basicNoTags, Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ResolverRuleExists(resourceName, &rule), - resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com."), + resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com"), resource.TestCheckResourceAttr(resourceName, "rule_type", "SYSTEM"), resource.TestCheckResourceAttr(resourceName, "share_status", "NOT_SHARED"), testAccCheckResourceAttrAccountID(resourceName, "owner_id"), @@ -124,7 +124,7 @@ func TestAccAwsRoute53ResolverRule_tags(t *testing.T) { Config: testAccRoute53ResolverRuleConfig_basicTags, Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ResolverRuleExists(resourceName, &rule), - resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com."), + resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com"), resource.TestCheckResourceAttr(resourceName, "rule_type", "SYSTEM"), resource.TestCheckResourceAttr(resourceName, "share_status", "NOT_SHARED"), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), @@ -140,7 +140,7 @@ func TestAccAwsRoute53ResolverRule_tags(t *testing.T) { Config: testAccRoute53ResolverRuleConfig_basicTagsChanged, Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ResolverRuleExists(resourceName, &rule), - resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com."), + resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com"), resource.TestCheckResourceAttr(resourceName, "rule_type", "SYSTEM"), resource.TestCheckResourceAttr(resourceName, "share_status", "NOT_SHARED"), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), @@ -151,7 +151,7 @@ func TestAccAwsRoute53ResolverRule_tags(t *testing.T) { Config: testAccRoute53ResolverRuleConfig_basicNoTags, Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ResolverRuleExists(resourceName, &rule), - resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com."), + resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com"), resource.TestCheckResourceAttr(resourceName, "rule_type", "SYSTEM"), resource.TestCheckResourceAttr(resourceName, "share_status", "NOT_SHARED"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), @@ -176,7 +176,7 @@ func TestAccAwsRoute53ResolverRule_updateName(t *testing.T) { Config: testAccRoute53ResolverRuleConfig_basicName(name1), Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ResolverRuleExists(resourceName, &rule1), - resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com."), + resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com"), resource.TestCheckResourceAttr(resourceName, "name", name1), resource.TestCheckResourceAttr(resourceName, "rule_type", "SYSTEM"), ), @@ -191,7 +191,7 @@ func TestAccAwsRoute53ResolverRule_updateName(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ResolverRuleExists(resourceName, &rule2), testAccCheckRoute53ResolverRulesSame(&rule2, &rule1), - resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com."), + resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com"), resource.TestCheckResourceAttr(resourceName, "name", name2), resource.TestCheckResourceAttr(resourceName, "rule_type", "SYSTEM"), ), @@ -216,7 +216,7 @@ func TestAccAwsRoute53ResolverRule_forward(t *testing.T) { Config: testAccRoute53ResolverRuleConfig_forward(name), Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ResolverRuleExists(resourceName, &rule1), - resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com."), + resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com"), resource.TestCheckResourceAttr(resourceName, "name", name), resource.TestCheckResourceAttr(resourceName, "rule_type", "FORWARD"), resource.TestCheckResourceAttrPair(resourceName, "resolver_endpoint_id", resourceNameEp1, "id"), @@ -237,7 +237,7 @@ func TestAccAwsRoute53ResolverRule_forward(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ResolverRuleExists(resourceName, &rule2), testAccCheckRoute53ResolverRulesSame(&rule2, &rule1), - resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com."), + resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com"), resource.TestCheckResourceAttr(resourceName, "name", name), resource.TestCheckResourceAttrPair(resourceName, "resolver_endpoint_id", resourceNameEp1, "id"), resource.TestCheckResourceAttr(resourceName, "rule_type", "FORWARD"), @@ -257,7 +257,7 @@ func TestAccAwsRoute53ResolverRule_forward(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ResolverRuleExists(resourceName, &rule3), testAccCheckRoute53ResolverRulesSame(&rule3, &rule2), - resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com."), + resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com"), resource.TestCheckResourceAttr(resourceName, "name", name), resource.TestCheckResourceAttrPair(resourceName, "resolver_endpoint_id", resourceNameEp2, "id"), resource.TestCheckResourceAttr(resourceName, "rule_type", "FORWARD"), @@ -291,7 +291,7 @@ func TestAccAwsRoute53ResolverRule_forwardEndpointRecreate(t *testing.T) { Config: testAccRoute53ResolverRuleConfig_forward(name), Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ResolverRuleExists(resourceName, &rule1), - resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com."), + resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com"), resource.TestCheckResourceAttr(resourceName, "name", name), resource.TestCheckResourceAttr(resourceName, "rule_type", "FORWARD"), resource.TestCheckResourceAttrPair(resourceName, "resolver_endpoint_id", resourceNameEp, "id"), @@ -307,7 +307,7 @@ func TestAccAwsRoute53ResolverRule_forwardEndpointRecreate(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ResolverRuleExists(resourceName, &rule2), testAccCheckRoute53ResolverRulesDifferent(&rule2, &rule1), - resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com."), + resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com"), resource.TestCheckResourceAttr(resourceName, "name", name), resource.TestCheckResourceAttr(resourceName, "rule_type", "FORWARD"), resource.TestCheckResourceAttrPair(resourceName, "resolver_endpoint_id", resourceNameEp, "id"), diff --git a/aws/resource_aws_route53_zone.go b/aws/resource_aws_route53_zone.go index f156814317f..1b3ebf53ddf 100644 --- a/aws/resource_aws_route53_zone.go +++ b/aws/resource_aws_route53_zone.go @@ -29,10 +29,14 @@ func resourceAwsRoute53Zone() *schema.Resource { Schema: map[string]*schema.Schema{ "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - DiffSuppressFunc: suppressRoute53ZoneNameWithTrailingDot, + // AWS Provider 3.0.0 - trailing period removed from name + // returned from API, no longer requiring custom DiffSuppressFunc; + // instead a StateFunc allows input to be provided + // with or without the trailing period + Type: schema.TypeString, + Required: true, + ForceNew: true, + StateFunc: trimTrailingPeriod, }, "comment": { @@ -179,7 +183,9 @@ func resourceAwsRoute53ZoneRead(d *schema.ResourceData, meta interface{}) error d.Set("comment", "") d.Set("delegation_set_id", "") - d.Set("name", output.HostedZone.Name) + // To be consistent with other AWS services (e.g. ACM) that do not accept a trailing period, + // we remove the suffix from the Hosted Zone Name returned from the API + d.Set("name", trimTrailingPeriod(aws.StringValue(output.HostedZone.Name))) d.Set("zone_id", cleanZoneID(aws.StringValue(output.HostedZone.Id))) var nameServers []string @@ -389,6 +395,22 @@ func cleanZoneID(ID string) string { return strings.TrimPrefix(ID, "/hostedzone/") } +// trimTrailingPeriod is used to remove the trailing period +// of "name" or "domain name" attributes often returned from +// the Route53 API or provided as user input +func trimTrailingPeriod(v interface{}) string { + var str string + switch value := v.(type) { + case *string: + str = *value + case string: + str = value + default: + return "" + } + return strings.TrimSuffix(str, ".") +} + func getNameServers(zoneId string, zoneName string, r53 *route53.Route53) ([]string, error) { resp, err := r53.ListResourceRecordSets(&route53.ListResourceRecordSetsInput{ HostedZoneId: aws.String(zoneId), diff --git a/aws/resource_aws_route53_zone_test.go b/aws/resource_aws_route53_zone_test.go index 1263dfbef7c..dca8a4d0549 100644 --- a/aws/resource_aws_route53_zone_test.go +++ b/aws/resource_aws_route53_zone_test.go @@ -48,6 +48,23 @@ func TestCleanChangeID(t *testing.T) { } } +func TestTrimTrailingPeriod(t *testing.T) { + cases := []struct { + Input, Output string + }{ + {"example.com", "example.com"}, + {"example.com.", "example.com"}, + {"www.example.com.", "www.example.com"}, + } + + for _, tc := range cases { + actual := trimTrailingPeriod(tc.Input) + if actual != tc.Output { + t.Fatalf("input: %s\noutput: %s", tc.Input, actual) + } + } +} + func TestAccAWSRoute53Zone_basic(t *testing.T) { var zone route53.GetHostedZoneOutput @@ -64,7 +81,7 @@ func TestAccAWSRoute53Zone_basic(t *testing.T) { Config: testAccRoute53ZoneConfig(zoneName), Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ZoneExists(resourceName, &zone), - resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("%s.", zoneName)), + resource.TestCheckResourceAttr(resourceName, "name", zoneName), resource.TestCheckResourceAttr(resourceName, "name_servers.#", "4"), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), resource.TestCheckResourceAttr(resourceName, "vpc.#", "0"), @@ -116,15 +133,15 @@ func TestAccAWSRoute53Zone_multiple(t *testing.T) { Config: testAccRoute53ZoneConfigMultiple(), Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ZoneExists("aws_route53_zone.test.0", &zone0), - testAccCheckDomainName(&zone0, "subdomain0.terraformtest.com."), + testAccCheckDomainName(&zone0, "subdomain0.terraformtest.com"), testAccCheckRoute53ZoneExists("aws_route53_zone.test.1", &zone1), - testAccCheckDomainName(&zone1, "subdomain1.terraformtest.com."), + testAccCheckDomainName(&zone1, "subdomain1.terraformtest.com"), testAccCheckRoute53ZoneExists("aws_route53_zone.test.2", &zone2), - testAccCheckDomainName(&zone2, "subdomain2.terraformtest.com."), + testAccCheckDomainName(&zone2, "subdomain2.terraformtest.com"), testAccCheckRoute53ZoneExists("aws_route53_zone.test.3", &zone3), - testAccCheckDomainName(&zone3, "subdomain3.terraformtest.com."), + testAccCheckDomainName(&zone3, "subdomain3.terraformtest.com"), testAccCheckRoute53ZoneExists("aws_route53_zone.test.4", &zone4), - testAccCheckDomainName(&zone4, "subdomain4.terraformtest.com."), + testAccCheckDomainName(&zone4, "subdomain4.terraformtest.com"), ), }, }, @@ -554,7 +571,10 @@ func testAccCheckDomainName(zone *route53.GetHostedZoneOutput, domain string) re return fmt.Errorf("Empty name in HostedZone for domain %s", domain) } - if *zone.HostedZone.Name == domain { + // To compare the Hosted Zone Domain Name returned from the API + // and that stored in the resource, it too must by cleaned of + // the trailing period + if trimTrailingPeriod(aws.StringValue(zone.HostedZone.Name)) == domain { return nil } @@ -564,7 +584,7 @@ func testAccCheckDomainName(zone *route53.GetHostedZoneOutput, domain string) re func testAccRoute53ZoneConfig(zoneName string) string { return fmt.Sprintf(` resource "aws_route53_zone" "test" { - name = "%s." + name = "%s" } `, zoneName) } @@ -583,7 +603,7 @@ func testAccRoute53ZoneConfigComment(zoneName, comment string) string { return fmt.Sprintf(` resource "aws_route53_zone" "test" { comment = %q - name = "%s." + name = "%s" } `, comment, zoneName) } @@ -594,7 +614,7 @@ resource "aws_route53_delegation_set" "test" {} resource "aws_route53_zone" "test" { delegation_set_id = "${aws_route53_delegation_set.test.id}" - name = "%s." + name = "%s" } `, zoneName) } @@ -620,7 +640,7 @@ resource "aws_route53_zone" "test" { func testAccRoute53ZoneConfigTagsSingle(zoneName, tag1Key, tag1Value string) string { return fmt.Sprintf(` resource "aws_route53_zone" "test" { - name = "%s." + name = "%s" tags = { %q = %q @@ -632,7 +652,7 @@ resource "aws_route53_zone" "test" { func testAccRoute53ZoneConfigTagsMultiple(zoneName, tag1Key, tag1Value, tag2Key, tag2Value string) string { return fmt.Sprintf(` resource "aws_route53_zone" "test" { - name = "%s." + name = "%s" tags = { %q = %q @@ -653,7 +673,7 @@ resource "aws_vpc" "test1" { } resource "aws_route53_zone" "test" { - name = "%s." + name = "%s" vpc { vpc_id = "${aws_vpc.test1.id}" @@ -681,7 +701,7 @@ resource "aws_vpc" "test2" { } resource "aws_route53_zone" "test" { - name = "%s." + name = "%s" vpc { vpc_id = "${aws_vpc.test1.id}" diff --git a/aws/resource_aws_ses_domain_identity.go b/aws/resource_aws_ses_domain_identity.go index 4dd77bd63e1..509b9e537cd 100644 --- a/aws/resource_aws_ses_domain_identity.go +++ b/aws/resource_aws_ses_domain_identity.go @@ -3,7 +3,6 @@ package aws import ( "fmt" "log" - "strings" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" @@ -26,12 +25,10 @@ func resourceAwsSesDomainIdentity() *schema.Resource { Computed: true, }, "domain": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - StateFunc: func(v interface{}) string { - return strings.TrimSuffix(v.(string), ".") - }, + Type: schema.TypeString, + Required: true, + ForceNew: true, + StateFunc: trimTrailingPeriod, }, "verification_token": { Type: schema.TypeString, @@ -45,7 +42,6 @@ func resourceAwsSesDomainIdentityCreate(d *schema.ResourceData, meta interface{} conn := meta.(*AWSClient).sesconn domainName := d.Get("domain").(string) - domainName = strings.TrimSuffix(domainName, ".") createOpts := &ses.VerifyDomainIdentityInput{ Domain: aws.String(domainName), diff --git a/aws/resource_aws_ses_domain_identity_verification.go b/aws/resource_aws_ses_domain_identity_verification.go index a14d0424fd0..48afeae96c6 100644 --- a/aws/resource_aws_ses_domain_identity_verification.go +++ b/aws/resource_aws_ses_domain_identity_verification.go @@ -3,7 +3,6 @@ package aws import ( "fmt" "log" - "strings" "time" "github.com/aws/aws-sdk-go/aws" @@ -25,12 +24,10 @@ func resourceAwsSesDomainIdentityVerification() *schema.Resource { Computed: true, }, "domain": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - StateFunc: func(v interface{}) string { - return strings.TrimSuffix(v.(string), ".") - }, + Type: schema.TypeString, + Required: true, + ForceNew: true, + StateFunc: trimTrailingPeriod, }, }, Timeouts: &schema.ResourceTimeout{ @@ -56,7 +53,7 @@ func getAwsSesIdentityVerificationAttributes(conn *ses.SES, domainName string) ( func resourceAwsSesDomainIdentityVerificationCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).sesconn - domainName := strings.TrimSuffix(d.Get("domain").(string), ".") + domainName := d.Get("domain").(string) err := resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError { att, err := getAwsSesIdentityVerificationAttributes(conn, domainName) if err != nil { diff --git a/website/docs/guides/version-3-upgrade.html.md b/website/docs/guides/version-3-upgrade.html.md index 09fd362d262..18c8f5e7c9d 100644 --- a/website/docs/guides/version-3-upgrade.html.md +++ b/website/docs/guides/version-3-upgrade.html.md @@ -23,6 +23,10 @@ Upgrade topics: - [Provider Custom Service Endpoint Updates](#provider-custom-service-endpoint-updates) - [Data Source: aws_availability_zones](#data-source-aws_availability_zones) - [Data Source: aws_lambda_invocation](#data-source-aws_lambda_invocation) +- [Data Source: aws_route53_resolver_rule](#data-source-aws_route53_resolver_rule) +- [Data Source: aws_route53_zone](#data-source-aws_route53_zone) +- [Resource: aws_acm_certificate](#resource-aws_acm_certificate) +- [Resource: aws_api_gateway_method_settings](#resource-aws_api_gateway_method_settings) - [Resource: aws_acm_certificate](#resource-aws_acm_certificate) - [Resource: aws_api_gateway_method_settings](#resource-aws_api_gateway_method_settings) - [Resource: aws_autoscaling_group](#resource-aws_autoscaling_group) @@ -42,6 +46,8 @@ Upgrade topics: - [Resource: aws_lb_listener_rule](#resource-aws_lb_listener_rule) - [Resource: aws_msk_cluster](#resource-aws_msk_cluster) - [Resource: aws_rds_cluster](#resource-aws_rds_cluster) +- [Resource: aws_route53_resolver_rule](#resource-aws_route53_resolver_rule) +- [Resource: aws_route53_zone](#resource-aws_route53_zone) - [Resource: aws_s3_bucket](#resource-aws_s3_bucket) - [Resource: aws_s3_bucket_metric](#resource-aws_s3_bucket_metric) - [Resource: aws_security_group](#resource-aws_security_group) @@ -209,6 +215,20 @@ output "lambda_result" { } ``` +## Data Source: aws_route53_resolver_rule + +### Removal of domain_name trailing period + +Previously the data-source returned the Resolver Rule Domain Name directly from the API, which included a `.` suffix. This proves difficult when many other AWS services do not accept this trailing period (e.g. ACM Certificate). This period is now automatically removed. For example, when the attribute would previously return a Resolver Rule Domain Name such as `example.com.`, the attribute now will be returned as `example.com`. +While the returned value will omit the trailing period, use of configurations with trailing periods will not be interrupted. + +## Data Source: aws_route53_zone + +### Removal of name trailing period + +Previously the data-source returned the Hosted Zone Domain Name directly from the API, which included a `.` suffix. This proves difficult when many other AWS services do not accept this trailing period (e.g. ACM Certificate). This period is now automatically removed. For example, when the attribute would previously return a Hosted Zone Domain Name such as `example.com.`, the attribute now will be returned as `example.com`. +While the returned value will omit the trailing period, use of configurations with trailing periods will not be interrupted. + ## Resource: aws_acm_certificate ### domain_validation_options Changed from List to Set @@ -1020,6 +1040,20 @@ resource "aws_msk_cluster" "example" { Previously when the `min_capacity` argument in a `scaling_configuration` block was not configured, the resource would default to 2. This behavior has been updated to align with the AWS RDS Cluster API default of 1. +## Resource: aws_route53_resolver_rule + +### Removal of domain_name trailing period + +Previously the resource returned the Resolver Rule Domain Name directly from the API, which included a `.` suffix. This proves difficult when many other AWS services do not accept this trailing period (e.g. ACM Certificate). This period is now automatically removed. For example, when the attribute would previously return a Resolver Rule Domain Name such as `example.com.`, the attribute now will be returned as `example.com`. +While the returned value will omit the trailing period, use of configurations with trailing periods will not be interrupted. + +## Resource: aws_route53_zone + +### Removal of name trailing period + +Previously the resource returned the Hosted Zone Domain Name directly from the API, which included a `.` suffix. This proves difficult when many other AWS services do not accept this trailing period (e.g. ACM Certificate). This period is now automatically removed. For example, when the attribute would previously return a Hosted Zone Domain Name such as `example.com.`, the attribute now will be returned as `example.com`. +While the returned value will omit the trailing period, use of configurations with trailing periods will not be interrupted. + ## Resource: aws_s3_bucket ### Removal of Automatic aws_s3_bucket_policy Import From 03dd714c8f22690899826d04227cd312a72c5c0b Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Mon, 27 Jul 2020 16:06:59 -0400 Subject: [PATCH 2/6] fixup acctests with trailing period and documentation --- aws/resource_aws_acm_certificate_test.go | 28 +++++++++--------- aws/resource_aws_route53_zone_test.go | 29 +++++++++---------- website/docs/guides/version-3-upgrade.html.md | 2 -- 3 files changed, 27 insertions(+), 32 deletions(-) diff --git a/aws/resource_aws_acm_certificate_test.go b/aws/resource_aws_acm_certificate_test.go index fb17ce1fc80..4391a56b391 100644 --- a/aws/resource_aws_acm_certificate_test.go +++ b/aws/resource_aws_acm_certificate_test.go @@ -301,11 +301,11 @@ func TestAccAWSAcmCertificate_rootAndWildcardSan(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(rootDomain)), resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "2"), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ - "domain_name": rootDomain, + "domain_name": trimTrailingPeriod(rootDomain), "resource_record_type": "CNAME", }), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ - "domain_name": wildcardDomain, + "domain_name": trimTrailingPeriod(wildcardDomain), "resource_record_type": "CNAME", }), resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation), @@ -342,11 +342,11 @@ func TestAccAWSAcmCertificate_san_single(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(domain)), resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "2"), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ - "domain_name": domain, + "domain_name": trimTrailingPeriod(domain), "resource_record_type": "CNAME", }), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ - "domain_name": sanDomain, + "domain_name": trimTrailingPeriod(sanDomain), "resource_record_type": "CNAME", }), resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation), @@ -384,15 +384,15 @@ func TestAccAWSAcmCertificate_san_multiple(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(domain)), resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "3"), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ - "domain_name": domain, + "domain_name": trimTrailingPeriod(domain), "resource_record_type": "CNAME", }), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ - "domain_name": sanDomain1, + "domain_name": trimTrailingPeriod(sanDomain1), "resource_record_type": "CNAME", }), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ - "domain_name": sanDomain2, + "domain_name": trimTrailingPeriod(sanDomain2), "resource_record_type": "CNAME", }), resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation), @@ -430,11 +430,11 @@ func TestAccAWSAcmCertificate_san_TrailingPeriod(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(domain)), resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "2"), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ - "domain_name": domain, + "domain_name": trimTrailingPeriod(domain), "resource_record_type": "CNAME", }), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ - "domain_name": strings.TrimSuffix(sanDomain, "."), + "domain_name": trimTrailingPeriod(sanDomain), "resource_record_type": "CNAME", }), resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation), @@ -470,7 +470,7 @@ func TestAccAWSAcmCertificate_wildcard(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(wildcardDomain)), resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "1"), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ - "domain_name": wildcardDomain, + "domain_name": trimTrailingPeriod(wildcardDomain), "resource_record_type": "CNAME", }), resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation), @@ -505,11 +505,11 @@ func TestAccAWSAcmCertificate_wildcardAndRootSan(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(wildcardDomain)), resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "2"), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ - "domain_name": rootDomain, + "domain_name": trimTrailingPeriod(rootDomain), "resource_record_type": "CNAME", }), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ - "domain_name": wildcardDomain, + "domain_name": trimTrailingPeriod(wildcardDomain), "resource_record_type": "CNAME", }), resource.TestCheckResourceAttr(resourceName, "status", acm.CertificateStatusPendingValidation), @@ -541,10 +541,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", rootDomain), + resource.TestCheckResourceAttr(resourceName, "domain_name", trimTrailingPeriod(rootDomain)), resource.TestCheckResourceAttr(resourceName, "domain_validation_options.#", "1"), tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "domain_validation_options.*", map[string]string{ - "domain_name": rootDomain, + "domain_name": trimTrailingPeriod(rootDomain), "resource_record_type": "CNAME", }), resource.TestCheckResourceAttr(resourceName, "subject_alternative_names.#", "0"), diff --git a/aws/resource_aws_route53_zone_test.go b/aws/resource_aws_route53_zone_test.go index dca8a4d0549..63f2528bd09 100644 --- a/aws/resource_aws_route53_zone_test.go +++ b/aws/resource_aws_route53_zone_test.go @@ -133,15 +133,15 @@ func TestAccAWSRoute53Zone_multiple(t *testing.T) { Config: testAccRoute53ZoneConfigMultiple(), Check: resource.ComposeTestCheckFunc( testAccCheckRoute53ZoneExists("aws_route53_zone.test.0", &zone0), - testAccCheckDomainName(&zone0, "subdomain0.terraformtest.com"), + testAccCheckDomainName(&zone0, "subdomain0.terraformtest.com."), testAccCheckRoute53ZoneExists("aws_route53_zone.test.1", &zone1), - testAccCheckDomainName(&zone1, "subdomain1.terraformtest.com"), + testAccCheckDomainName(&zone1, "subdomain1.terraformtest.com."), testAccCheckRoute53ZoneExists("aws_route53_zone.test.2", &zone2), - testAccCheckDomainName(&zone2, "subdomain2.terraformtest.com"), + testAccCheckDomainName(&zone2, "subdomain2.terraformtest.com."), testAccCheckRoute53ZoneExists("aws_route53_zone.test.3", &zone3), - testAccCheckDomainName(&zone3, "subdomain3.terraformtest.com"), + testAccCheckDomainName(&zone3, "subdomain3.terraformtest.com."), testAccCheckRoute53ZoneExists("aws_route53_zone.test.4", &zone4), - testAccCheckDomainName(&zone4, "subdomain4.terraformtest.com"), + testAccCheckDomainName(&zone4, "subdomain4.terraformtest.com."), ), }, }, @@ -571,10 +571,7 @@ func testAccCheckDomainName(zone *route53.GetHostedZoneOutput, domain string) re return fmt.Errorf("Empty name in HostedZone for domain %s", domain) } - // To compare the Hosted Zone Domain Name returned from the API - // and that stored in the resource, it too must by cleaned of - // the trailing period - if trimTrailingPeriod(aws.StringValue(zone.HostedZone.Name)) == domain { + if aws.StringValue(zone.HostedZone.Name) == domain { return nil } @@ -584,7 +581,7 @@ func testAccCheckDomainName(zone *route53.GetHostedZoneOutput, domain string) re func testAccRoute53ZoneConfig(zoneName string) string { return fmt.Sprintf(` resource "aws_route53_zone" "test" { - name = "%s" + name = "%s." } `, zoneName) } @@ -603,7 +600,7 @@ func testAccRoute53ZoneConfigComment(zoneName, comment string) string { return fmt.Sprintf(` resource "aws_route53_zone" "test" { comment = %q - name = "%s" + name = "%s." } `, comment, zoneName) } @@ -614,7 +611,7 @@ resource "aws_route53_delegation_set" "test" {} resource "aws_route53_zone" "test" { delegation_set_id = "${aws_route53_delegation_set.test.id}" - name = "%s" + name = "%s." } `, zoneName) } @@ -640,7 +637,7 @@ resource "aws_route53_zone" "test" { func testAccRoute53ZoneConfigTagsSingle(zoneName, tag1Key, tag1Value string) string { return fmt.Sprintf(` resource "aws_route53_zone" "test" { - name = "%s" + name = "%s." tags = { %q = %q @@ -652,7 +649,7 @@ resource "aws_route53_zone" "test" { func testAccRoute53ZoneConfigTagsMultiple(zoneName, tag1Key, tag1Value, tag2Key, tag2Value string) string { return fmt.Sprintf(` resource "aws_route53_zone" "test" { - name = "%s" + name = "%s." tags = { %q = %q @@ -673,7 +670,7 @@ resource "aws_vpc" "test1" { } resource "aws_route53_zone" "test" { - name = "%s" + name = "%s." vpc { vpc_id = "${aws_vpc.test1.id}" @@ -701,7 +698,7 @@ resource "aws_vpc" "test2" { } resource "aws_route53_zone" "test" { - name = "%s" + name = "%s." vpc { vpc_id = "${aws_vpc.test1.id}" diff --git a/website/docs/guides/version-3-upgrade.html.md b/website/docs/guides/version-3-upgrade.html.md index 18c8f5e7c9d..1cb69df5980 100644 --- a/website/docs/guides/version-3-upgrade.html.md +++ b/website/docs/guides/version-3-upgrade.html.md @@ -27,8 +27,6 @@ Upgrade topics: - [Data Source: aws_route53_zone](#data-source-aws_route53_zone) - [Resource: aws_acm_certificate](#resource-aws_acm_certificate) - [Resource: aws_api_gateway_method_settings](#resource-aws_api_gateway_method_settings) -- [Resource: aws_acm_certificate](#resource-aws_acm_certificate) -- [Resource: aws_api_gateway_method_settings](#resource-aws_api_gateway_method_settings) - [Resource: aws_autoscaling_group](#resource-aws_autoscaling_group) - [Resource: aws_cognito_user_pool](#resource-aws_cognito_user_pool) - [Resource: aws_dx_gateway](#resource-aws_dx_gateway) From 3ae10dd5c20d596f023a359cf4a628977d860f81 Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Tue, 28 Jul 2020 07:36:23 -0400 Subject: [PATCH 3/6] revert domain name trim at Create time and update docs --- aws/resource_aws_acm_certificate.go | 2 +- aws/resource_aws_route53_record.go | 2 +- aws/resource_aws_ses_domain_identity.go | 2 +- website/docs/guides/version-3-upgrade.html.md | 13 +++++++++---- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_acm_certificate.go b/aws/resource_aws_acm_certificate.go index 17535323b06..447c7131d6b 100644 --- a/aws/resource_aws_acm_certificate.go +++ b/aws/resource_aws_acm_certificate.go @@ -225,7 +225,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(d.Get("domain_name").(string)), + DomainName: aws.String(trimTrailingPeriod(d.Get("domain_name").(string))), IdempotencyToken: aws.String(resource.PrefixedUniqueId("tf")), // 32 character limit Options: expandAcmCertificateOptions(d.Get("options").([]interface{})), } diff --git a/aws/resource_aws_route53_record.go b/aws/resource_aws_route53_record.go index 1e270ad3731..4b96ffbbadd 100644 --- a/aws/resource_aws_route53_record.go +++ b/aws/resource_aws_route53_record.go @@ -919,7 +919,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(name) + rn := strings.ToLower(trimTrailingPeriod(name)) zone = strings.TrimSuffix(zone, ".") if !strings.HasSuffix(rn, zone) { if len(name) == 0 { diff --git a/aws/resource_aws_ses_domain_identity.go b/aws/resource_aws_ses_domain_identity.go index 509b9e537cd..53b6da85778 100644 --- a/aws/resource_aws_ses_domain_identity.go +++ b/aws/resource_aws_ses_domain_identity.go @@ -41,7 +41,7 @@ func resourceAwsSesDomainIdentity() *schema.Resource { func resourceAwsSesDomainIdentityCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).sesconn - domainName := d.Get("domain").(string) + domainName := trimTrailingPeriod(d.Get("domain").(string)) createOpts := &ses.VerifyDomainIdentityInput{ Domain: aws.String(domainName), diff --git a/website/docs/guides/version-3-upgrade.html.md b/website/docs/guides/version-3-upgrade.html.md index 1cb69df5980..3ae9d5b3d1e 100644 --- a/website/docs/guides/version-3-upgrade.html.md +++ b/website/docs/guides/version-3-upgrade.html.md @@ -215,20 +215,25 @@ output "lambda_result" { ## Data Source: aws_route53_resolver_rule -### Removal of domain_name trailing period +### Removal of trailing period in domain_name argument Previously the data-source returned the Resolver Rule Domain Name directly from the API, which included a `.` suffix. This proves difficult when many other AWS services do not accept this trailing period (e.g. ACM Certificate). This period is now automatically removed. For example, when the attribute would previously return a Resolver Rule Domain Name such as `example.com.`, the attribute now will be returned as `example.com`. While the returned value will omit the trailing period, use of configurations with trailing periods will not be interrupted. ## Data Source: aws_route53_zone -### Removal of name trailing period +### Removal of trailing period in name argument Previously the data-source returned the Hosted Zone Domain Name directly from the API, which included a `.` suffix. This proves difficult when many other AWS services do not accept this trailing period (e.g. ACM Certificate). This period is now automatically removed. For example, when the attribute would previously return a Hosted Zone Domain Name such as `example.com.`, the attribute now will be returned as `example.com`. While the returned value will omit the trailing period, use of configurations with trailing periods will not be interrupted. ## Resource: aws_acm_certificate +### Removal of trailing period in domain_name argument and domain_validation_options.domain_name attribute + +Previously the resource returned the Fully Qualified Domain Name of the certificate directly from the API, which included a `.` suffix. This proves difficult when many other AWS services do not accept this trailing period. This period is now automatically removed. For example, when `domain_name` or `domain_validation_options.domain_name` would previously return a Fully Qualified Domain Name such as `example.com.`, it now will be returned as `example.com`. +While the returned value for the `domain_name` argument will omit the trailing period, use of configurations with the trailing period in will not be interrupted. + ### domain_validation_options Changed from List to Set Previously, the `domain_validation_options` attribute was a list type and completely unknown until after an initial `terraform apply`. This generally required complicated configuration workarounds to properly create DNS validation records since referencing this attribute directly could produce errors similar to the below: @@ -1040,14 +1045,14 @@ Previously when the `min_capacity` argument in a `scaling_configuration` block w ## Resource: aws_route53_resolver_rule -### Removal of domain_name trailing period +### Removal of trailing period in domain_name argument Previously the resource returned the Resolver Rule Domain Name directly from the API, which included a `.` suffix. This proves difficult when many other AWS services do not accept this trailing period (e.g. ACM Certificate). This period is now automatically removed. For example, when the attribute would previously return a Resolver Rule Domain Name such as `example.com.`, the attribute now will be returned as `example.com`. While the returned value will omit the trailing period, use of configurations with trailing periods will not be interrupted. ## Resource: aws_route53_zone -### Removal of name trailing period +### Removal of trailing period in name argument Previously the resource returned the Hosted Zone Domain Name directly from the API, which included a `.` suffix. This proves difficult when many other AWS services do not accept this trailing period (e.g. ACM Certificate). This period is now automatically removed. For example, when the attribute would previously return a Hosted Zone Domain Name such as `example.com.`, the attribute now will be returned as `example.com`. While the returned value will omit the trailing period, use of configurations with trailing periods will not be interrupted. From dc19585e73c7716ff655de13444cbad7064f2d55 Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Wed, 29 Jul 2020 20:03:50 -0400 Subject: [PATCH 4/6] CR updates to remove custom period handling and add validation instead --- aws/resource_aws_acm_certificate.go | 29 ++++--- aws/resource_aws_acm_certificate_test.go | 78 ++++++++----------- aws/resource_aws_route53_record.go | 9 ++- aws/resource_aws_route53_record_test.go | 25 +++--- aws/resource_aws_ses_domain_identity.go | 12 +-- aws/resource_aws_ses_domain_identity_test.go | 10 +-- ...ce_aws_ses_domain_identity_verification.go | 10 ++- website/docs/guides/version-3-upgrade.html.md | 5 -- 8 files changed, 83 insertions(+), 95 deletions(-) diff --git a/aws/resource_aws_acm_certificate.go b/aws/resource_aws_acm_certificate.go index 447c7131d6b..699e8fb93f7 100644 --- a/aws/resource_aws_acm_certificate.go +++ b/aws/resource_aws_acm_certificate.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "log" + "regexp" "strings" "time" @@ -58,14 +59,14 @@ 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, @@ -73,11 +74,13 @@ func resourceAwsAcmCertificate() *schema.Resource { 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"}, @@ -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 { @@ -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{})), } @@ -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) @@ -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), diff --git a/aws/resource_aws_acm_certificate_test.go b/aws/resource_aws_acm_certificate_test.go index 4391a56b391..29635573ddc 100644 --- a/aws/resource_aws_acm_certificate_test.go +++ b/aws/resource_aws_acm_certificate_test.go @@ -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"), @@ -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), @@ -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), @@ -249,10 +249,11 @@ 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) }, @@ -260,25 +261,8 @@ func TestAccAWSAcmCertificate_root_TrailingPeriod(t *testing.T) { 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\)`), }, }, }) @@ -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), ), @@ -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), ), @@ -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), @@ -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), @@ -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), @@ -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), @@ -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"), diff --git a/aws/resource_aws_route53_record.go b/aws/resource_aws_route53_record.go index 4b96ffbbadd..ab70637512e 100644 --- a/aws/resource_aws_route53_record.go +++ b/aws/resource_aws_route53_record.go @@ -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": { @@ -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 { diff --git a/aws/resource_aws_route53_record_test.go b/aws/resource_aws_route53_record_test.go index 52dfcec4caa..2f480800d7f 100644 --- a/aws/resource_aws_route53_record_test.go +++ b/aws/resource_aws_route53_record_test.go @@ -205,7 +205,7 @@ func TestAccAWSRoute53Record_disappears_MultipleRecords(t *testing.T) { } func TestAccAWSRoute53Record_basic_fqdn(t *testing.T) { - var record1, record2 route53.ResourceRecordSet + var record1 route53.ResourceRecordSet resourceName := "aws_route53_record.default" resource.ParallelTest(t, resource.TestCase{ @@ -226,18 +226,21 @@ func TestAccAWSRoute53Record_basic_fqdn(t *testing.T) { ImportStateVerify: true, ImportStateVerifyIgnore: []string{"allow_overwrite", "weight"}, }, + }, + }) +} + +// Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13510 +func TestAccAWSRoute53Record_basic_name_trailingPeriod(t *testing.T) { - // Ensure that changing the name to include a trailing "dot" results in - // nothing happening, because the name is stripped of trailing dots on - // save. Otherwise, an update would occur and due to the - // create_before_destroy, the record would actually be destroyed, and a - // non-empty plan would appear, and the record will fail to exist in - // testAccCheckRoute53RecordExists + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckRoute53RecordDestroy, + Steps: []resource.TestStep{ { - Config: testAccRoute53RecordConfig_fqdn_no_op, - Check: resource.ComposeTestCheckFunc( - testAccCheckRoute53RecordExists(resourceName, &record2), - ), + Config: testAccRoute53RecordConfig_fqdn_no_op, + ExpectError: regexp.MustCompile(`config is invalid: invalid value for name \(cannot end with a period\)`), }, }, }) diff --git a/aws/resource_aws_ses_domain_identity.go b/aws/resource_aws_ses_domain_identity.go index 53b6da85778..3ec2813e7ee 100644 --- a/aws/resource_aws_ses_domain_identity.go +++ b/aws/resource_aws_ses_domain_identity.go @@ -3,11 +3,13 @@ package aws import ( "fmt" "log" + "regexp" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/ses" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" ) func resourceAwsSesDomainIdentity() *schema.Resource { @@ -25,10 +27,10 @@ func resourceAwsSesDomainIdentity() *schema.Resource { Computed: true, }, "domain": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - StateFunc: trimTrailingPeriod, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringDoesNotMatch(regexp.MustCompile(`\.$`), "cannot end with a period"), }, "verification_token": { Type: schema.TypeString, @@ -41,7 +43,7 @@ func resourceAwsSesDomainIdentity() *schema.Resource { func resourceAwsSesDomainIdentityCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).sesconn - domainName := trimTrailingPeriod(d.Get("domain").(string)) + domainName := d.Get("domain").(string) createOpts := &ses.VerifyDomainIdentityInput{ Domain: aws.String(domainName), diff --git a/aws/resource_aws_ses_domain_identity_test.go b/aws/resource_aws_ses_domain_identity_test.go index 60c7991de10..d9d2de3abfc 100644 --- a/aws/resource_aws_ses_domain_identity_test.go +++ b/aws/resource_aws_ses_domain_identity_test.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "regexp" "strings" "testing" @@ -109,6 +110,8 @@ func TestAccAWSSESDomainIdentity_disappears(t *testing.T) { }) } +// TestAccAWSSESDomainIdentity_trailingPeriod updated in 3.0 to account for domain plan-time validation +// Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13510 func TestAccAWSSESDomainIdentity_trailingPeriod(t *testing.T) { domain := fmt.Sprintf( "%s.terraformtesting.com.", @@ -120,11 +123,8 @@ func TestAccAWSSESDomainIdentity_trailingPeriod(t *testing.T) { CheckDestroy: testAccCheckAwsSESDomainIdentityDestroy, Steps: []resource.TestStep{ { - Config: testAccAwsSESDomainIdentityConfig(domain), - Check: resource.ComposeTestCheckFunc( - testAccCheckAwsSESDomainIdentityExists("aws_ses_domain_identity.test"), - testAccCheckAwsSESDomainIdentityArn("aws_ses_domain_identity.test", domain), - ), + Config: testAccAwsSESDomainIdentityConfig(domain), + ExpectError: regexp.MustCompile(`config is invalid: invalid value for domain \(cannot end with a period\)`), }, }, }) diff --git a/aws/resource_aws_ses_domain_identity_verification.go b/aws/resource_aws_ses_domain_identity_verification.go index 48afeae96c6..b1086b38f27 100644 --- a/aws/resource_aws_ses_domain_identity_verification.go +++ b/aws/resource_aws_ses_domain_identity_verification.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "regexp" "time" "github.com/aws/aws-sdk-go/aws" @@ -10,6 +11,7 @@ import ( "github.com/aws/aws-sdk-go/service/ses" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" ) func resourceAwsSesDomainIdentityVerification() *schema.Resource { @@ -24,10 +26,10 @@ func resourceAwsSesDomainIdentityVerification() *schema.Resource { Computed: true, }, "domain": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - StateFunc: trimTrailingPeriod, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringDoesNotMatch(regexp.MustCompile(`\.$`), "cannot end with a period"), }, }, Timeouts: &schema.ResourceTimeout{ diff --git a/website/docs/guides/version-3-upgrade.html.md b/website/docs/guides/version-3-upgrade.html.md index 3ae9d5b3d1e..89f4d82021c 100644 --- a/website/docs/guides/version-3-upgrade.html.md +++ b/website/docs/guides/version-3-upgrade.html.md @@ -229,11 +229,6 @@ While the returned value will omit the trailing period, use of configurations wi ## Resource: aws_acm_certificate -### Removal of trailing period in domain_name argument and domain_validation_options.domain_name attribute - -Previously the resource returned the Fully Qualified Domain Name of the certificate directly from the API, which included a `.` suffix. This proves difficult when many other AWS services do not accept this trailing period. This period is now automatically removed. For example, when `domain_name` or `domain_validation_options.domain_name` would previously return a Fully Qualified Domain Name such as `example.com.`, it now will be returned as `example.com`. -While the returned value for the `domain_name` argument will omit the trailing period, use of configurations with the trailing period in will not be interrupted. - ### domain_validation_options Changed from List to Set Previously, the `domain_validation_options` attribute was a list type and completely unknown until after an initial `terraform apply`. This generally required complicated configuration workarounds to properly create DNS validation records since referencing this attribute directly could produce errors similar to the below: From 9eb31470cbdc84c403fd919f89fc583631934271 Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Thu, 30 Jul 2020 12:10:07 -0400 Subject: [PATCH 5/6] update route53 record to allow trailing period in name and revert acm cert computed attr val --- aws/resource_aws_acm_certificate.go | 16 +++++++++----- aws/resource_aws_route53_record.go | 10 ++++----- aws/resource_aws_route53_record_test.go | 29 ++++++++++++------------- 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/aws/resource_aws_acm_certificate.go b/aws/resource_aws_acm_certificate.go index 699e8fb93f7..e3bcb42b288 100644 --- a/aws/resource_aws_acm_certificate.go +++ b/aws/resource_aws_acm_certificate.go @@ -77,10 +77,8 @@ func resourceAwsAcmCertificate() *schema.Resource { // AWS Provider 3.0.0 aws_route53_zone references no longer contain a // 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"), - ), + Type: schema.TypeString, + ValidateFunc: validation.StringDoesNotMatch(regexp.MustCompile(`\.$`), "cannot end with a period"), }, Set: schema.HashString, ConflictsWith: []string{"private_key", "certificate_body", "certificate_chain"}, @@ -165,6 +163,9 @@ 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{}{ + // AWS Provider 3.0 -- plan-time validation prevents "domain_name" + // argument to accept a string with trailing period; thus, trim of trailing period + // no longer required here "domain_name": diff.Get("domain_name").(string), }} @@ -177,7 +178,10 @@ func resourceAwsAcmCertificate() *schema.Resource { } m := map[string]interface{}{ - "domain_name": strings.TrimSuffix(san, "."), + // AWS Provider 3.0 -- plan-time validation prevents "subject_alternative_names" + // argument to accept strings with trailing period; thus, trim of trailing period + // no longer required here + "domain_name": san, } domainValidationOptionsList = append(domainValidationOptionsList, m) @@ -244,7 +248,7 @@ func resourceAwsAcmCertificateCreateRequested(d *schema.ResourceData, meta inter if sans, ok := d.GetOk("subject_alternative_names"); ok { subjectAlternativeNames := make([]*string, len(sans.(*schema.Set).List())) for i, sanRaw := range sans.(*schema.Set).List() { - subjectAlternativeNames[i] = aws.String(strings.TrimSuffix(sanRaw.(string), ".")) + subjectAlternativeNames[i] = aws.String(sanRaw.(string)) } params.SubjectAlternativeNames = subjectAlternativeNames } diff --git a/aws/resource_aws_route53_record.go b/aws/resource_aws_route53_record.go index ab70637512e..94982dca267 100644 --- a/aws/resource_aws_route53_record.go +++ b/aws/resource_aws_route53_record.go @@ -41,12 +41,12 @@ func resourceAwsRoute53Record() *schema.Resource { Required: true, ForceNew: true, StateFunc: func(v interface{}) string { - // AWS Provider 3.0.0 aws_route53_zone references no longer contain a - // trailing period, no longer requiring the custom StateFunc + // AWS Provider aws_acm_certification.domain_validation_options.resource_record_name + // references (and perhaps others) contain a trailing period, requiring a custom StateFunc // to trim the string to prevent Route53 API error - return strings.ToLower(v.(string)) + value := strings.TrimSuffix(v.(string), ".") + return strings.ToLower(value) }, - ValidateFunc: validation.StringDoesNotMatch(regexp.MustCompile(`\.$`), "cannot end with a period"), }, "fqdn": { @@ -922,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(name) + rn := strings.ToLower(strings.TrimSuffix(name, ".")) zone = strings.TrimSuffix(zone, ".") if !strings.HasSuffix(rn, zone) { if len(name) == 0 { diff --git a/aws/resource_aws_route53_record_test.go b/aws/resource_aws_route53_record_test.go index 2f480800d7f..4589252b5c5 100644 --- a/aws/resource_aws_route53_record_test.go +++ b/aws/resource_aws_route53_record_test.go @@ -41,10 +41,12 @@ func TestExpandRecordName(t *testing.T) { Input, Output string }{ {"www", "www.nonexample.com"}, + {"www.", "www.nonexample.com"}, {"dev.www", "dev.www.nonexample.com"}, {"*", "*.nonexample.com"}, {"nonexample.com", "nonexample.com"}, {"test.nonexample.com", "test.nonexample.com"}, + {"test.nonexample.com.", "test.nonexample.com"}, } zone_name := "nonexample.com" @@ -205,7 +207,7 @@ func TestAccAWSRoute53Record_disappears_MultipleRecords(t *testing.T) { } func TestAccAWSRoute53Record_basic_fqdn(t *testing.T) { - var record1 route53.ResourceRecordSet + var record1, record2 route53.ResourceRecordSet resourceName := "aws_route53_record.default" resource.ParallelTest(t, resource.TestCase{ @@ -226,21 +228,18 @@ func TestAccAWSRoute53Record_basic_fqdn(t *testing.T) { ImportStateVerify: true, ImportStateVerifyIgnore: []string{"allow_overwrite", "weight"}, }, - }, - }) -} - -// Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/13510 -func TestAccAWSRoute53Record_basic_name_trailingPeriod(t *testing.T) { - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckRoute53RecordDestroy, - Steps: []resource.TestStep{ + // Ensure that changing the name to include a trailing "dot" results in + // nothing happening, because the name is stripped of trailing dots on + // save. Otherwise, an update would occur and due to the + // create_before_destroy, the record would actually be destroyed, and a + // non-empty plan would appear, and the record will fail to exist in + // testAccCheckRoute53RecordExists { - Config: testAccRoute53RecordConfig_fqdn_no_op, - ExpectError: regexp.MustCompile(`config is invalid: invalid value for name \(cannot end with a period\)`), + Config: testAccRoute53RecordConfig_fqdn_no_op, + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53RecordExists(resourceName, &record2), + ), }, }, }) @@ -1935,7 +1934,7 @@ resource "aws_route53_zone" "main" { } resource "aws_route53_record" "sample" { - zone_id = "${aws_route53_zone.main.zone_id}" + zone_id = "${aws_route53_zone.main.zone_id}" name = "sample" type = "CNAME" ttl = "30" From 45cc659c61ccdc8e5b00115aeee9cc2c773963cf Mon Sep 17 00:00:00 2001 From: Angie Pinilla Date: Thu, 30 Jul 2020 12:42:33 -0400 Subject: [PATCH 6/6] bring back trimming of name at import time --- aws/resource_aws_route53_record.go | 1 + aws/resource_aws_route53_record_test.go | 44 ++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_route53_record.go b/aws/resource_aws_route53_record.go index 94982dca267..68a9c7b7039 100644 --- a/aws/resource_aws_route53_record.go +++ b/aws/resource_aws_route53_record.go @@ -977,5 +977,6 @@ func parseRecordId(id string) [4]string { } } } + recName = strings.TrimSuffix(recName, ".") return [4]string{recZone, recName, recType, recSet} } diff --git a/aws/resource_aws_route53_record_test.go b/aws/resource_aws_route53_record_test.go index 4589252b5c5..d04ada305be 100644 --- a/aws/resource_aws_route53_record_test.go +++ b/aws/resource_aws_route53_record_test.go @@ -83,7 +83,7 @@ func TestParseRecordId(t *testing.T) { Input, Zone, Name, Type, Set string }{ {"ABCDEF_test.notexample.com_A", "ABCDEF", "test.notexample.com", "A", ""}, - {"ABCDEF_test.notexample.com_A", "ABCDEF", "test.notexample.com", "A", ""}, + {"ABCDEF_test.notexample.com._A", "ABCDEF", "test.notexample.com", "A", ""}, {"ABCDEF_test.notexample.com_A_set1", "ABCDEF", "test.notexample.com", "A", "set1"}, {"ABCDEF__underscore.notexample.com_A", "ABCDEF", "_underscore.notexample.com", "A", ""}, {"ABCDEF__underscore.notexample.com_A_set1", "ABCDEF", "_underscore.notexample.com", "A", "set1"}, @@ -245,6 +245,34 @@ func TestAccAWSRoute53Record_basic_fqdn(t *testing.T) { }) } +// TestAccAWSRoute53Record_basic_trailingPeriodAndZoneID ensures an aws_route53_record +// created with a name configured with a trailing period and explicit zone_id gets imported correctly +func TestAccAWSRoute53Record_basic_trailingPeriodAndZoneID(t *testing.T) { + var record1 route53.ResourceRecordSet + resourceName := "aws_route53_record.default" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: resourceName, + Providers: testAccProviders, + CheckDestroy: testAccCheckRoute53RecordDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRoute53RecordConfig_nameWithTrailingPeriod, + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53RecordExists(resourceName, &record1), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"allow_overwrite", "weight"}, + }, + }, + }) +} + func TestAccAWSRoute53Record_txtSupport(t *testing.T) { var record1 route53.ResourceRecordSet resourceName := "aws_route53_record.default" @@ -1177,6 +1205,20 @@ resource "aws_route53_record" "default" { } ` +const testAccRoute53RecordConfig_nameWithTrailingPeriod = ` +resource "aws_route53_zone" "main" { + name = "notexample.com" +} + +resource "aws_route53_record" "default" { + zone_id = "${aws_route53_zone.main.zone_id}" + name = "www.NOTexamplE.com." + type = "A" + ttl = "30" + records = ["127.0.0.1", "127.0.0.27"] +} +` + const testAccRoute53RecordConfigMultiple = ` resource "aws_route53_zone" "test" { name = "notexample.com"