diff --git a/.github/workflows/tests_terraform_examples.yml b/.github/workflows/tests_terraform_examples.yml
index b1a5f7054..12790048e 100644
--- a/.github/workflows/tests_terraform_examples.yml
+++ b/.github/workflows/tests_terraform_examples.yml
@@ -33,4 +33,9 @@ jobs:
cd other_langs/terraform/${{ matrix.service }}
terraform init
terraform apply --auto-approve
+ echo "Verify nothing changes when ACM certificates are validated"
+ sleep 30
+ terraform plan -detailed-exitcode
+ sleep 30
+ terraform plan -detailed-exitcode
terraform apply -destroy --auto-approve
diff --git a/moto/acm/models.py b/moto/acm/models.py
index 8d7bcf4c8..95435983c 100644
--- a/moto/acm/models.py
+++ b/moto/acm/models.py
@@ -343,24 +343,22 @@ class CertBundle(BaseModel):
domain_names = set(sans + [self.common_name])
validation_options = []
- if self.status == "PENDING_VALIDATION":
- for san in domain_names:
- resource_record = {
- "Name": f"_d930b28be6c5927595552b219965053e.{san}.",
- "Type": "CNAME",
- "Value": "_c9edd76ee4a0e2a74388032f3861cc50.ykybfrwcxw.acm-validations.aws.",
+ for san in domain_names:
+ resource_record = {
+ "Name": f"_d930b28be6c5927595552b219965053e.{san}.",
+ "Type": "CNAME",
+ "Value": "_c9edd76ee4a0e2a74388032f3861cc50.ykybfrwcxw.acm-validations.aws.",
+ }
+ validation_options.append(
+ {
+ "DomainName": san,
+ "ValidationDomain": san,
+ "ValidationStatus": self.status,
+ "ValidationMethod": "DNS",
+ "ResourceRecord": resource_record,
}
- validation_options.append(
- {
- "DomainName": san,
- "ValidationDomain": san,
- "ValidationStatus": self.status,
- "ValidationMethod": "DNS",
- "ResourceRecord": resource_record,
- }
- )
- else:
- validation_options = [{"DomainName": name} for name in domain_names]
+ )
+
result["Certificate"]["DomainValidationOptions"] = validation_options
if self.type == "IMPORTED":
diff --git a/moto/route53/models.py b/moto/route53/models.py
index 409d992ff..ccfd5dc4d 100644
--- a/moto/route53/models.py
+++ b/moto/route53/models.py
@@ -208,6 +208,7 @@ class RecordSet(CloudFormationModel):
self.alias_target = kwargs.get("AliasTarget", [])
self.failover = kwargs.get("Failover", [])
self.geo_location = kwargs.get("GeoLocation", [])
+ self.multi_value = kwargs.get("MultiValueAnswer")
@staticmethod
def cloudformation_name_type() -> str:
diff --git a/moto/route53/responses.py b/moto/route53/responses.py
index 7227f85f5..6350c71bc 100644
--- a/moto/route53/responses.py
+++ b/moto/route53/responses.py
@@ -562,6 +562,9 @@ LIST_RRSET_RESPONSE = """
{% if record.failover %}
{{ record.failover }}
{% endif %}
+ {% if record.multi_value %}
+ {{ record.multi_value }}
+ {% endif %}
{% if record.geo_location %}
{% for geo_key in ['ContinentCode','CountryCode','SubdivisionCode'] %}
diff --git a/tests/test_acm/test_acm.py b/tests/test_acm/test_acm.py
index d2943d801..c6704c5ed 100644
--- a/tests/test_acm/test_acm.py
+++ b/tests/test_acm/test_acm.py
@@ -1,5 +1,6 @@
import os
import uuid
+from time import sleep
from unittest import SkipTest, mock
import boto3
@@ -180,7 +181,6 @@ def test_describe_certificate():
assert len(resp["Certificate"]["DomainValidationOptions"]) == 1
validation_option = resp["Certificate"]["DomainValidationOptions"][0]
assert validation_option["DomainName"] == SERVER_COMMON_NAME
- assert "ValidationDomain" not in validation_option
@mock_acm
@@ -388,7 +388,10 @@ def test_request_certificate():
@mock_acm
+@mock.patch("moto.settings.ACM_VALIDATION_WAIT", 1)
def test_request_certificate_with_optional_arguments():
+ if not settings.TEST_DECORATOR_MODE:
+ raise SkipTest("Can only change setting in DecoratorMode")
client = boto3.client("acm", region_name="eu-central-1")
token = str(uuid.uuid4())
@@ -406,12 +409,21 @@ def test_request_certificate_with_optional_arguments():
arn_1 = resp["CertificateArn"]
cert = client.describe_certificate(CertificateArn=arn_1)["Certificate"]
+ assert cert["Status"] == "PENDING_VALIDATION"
assert len(cert["SubjectAlternativeNames"]) == 3
- assert len(cert["DomainValidationOptions"]) == 3
- assert {option["DomainName"] for option in cert["DomainValidationOptions"]} == set(
+ validation_options = cert["DomainValidationOptions"].copy()
+ assert len(validation_options) == 3
+ assert {option["DomainName"] for option in validation_options} == set(
cert["SubjectAlternativeNames"]
)
+ # Verify SAN's are still the same, even after the Certificate is validated
+ sleep(2)
+ for opt in validation_options:
+ opt["ValidationStatus"] = "ISSUED"
+ cert = client.describe_certificate(CertificateArn=arn_1)["Certificate"]
+ assert cert["DomainValidationOptions"] == validation_options
+
resp = client.list_tags_for_certificate(CertificateArn=arn_1)
tags = {item["Key"]: item.get("Value", "__NONE__") for item in resp["Tags"]}
assert len(tags) == 2
diff --git a/tests/test_route53/test_route53.py b/tests/test_route53/test_route53.py
index 5838cc5a1..149e34958 100644
--- a/tests/test_route53/test_route53.py
+++ b/tests/test_route53/test_route53.py
@@ -809,6 +809,7 @@ def test_change_resource_record_sets_crud_valid_with_special_xml_chars(
assert cname_record_detail["ResourceRecords"] == [
{"Value": "SomeInitialValue&NewValue"}
]
+ assert cname_record_detail.get("MultiValueAnswer") == multi_value_answer
# Delete record.
delete_payload = {