Skip to content
This repository was archived by the owner on Mar 23, 2026. It is now read-only.

Commit 977e8dd

Browse files
committed
Work in review suggestions
1 parent d6e9184 commit 977e8dd

File tree

4 files changed

+64
-95
lines changed

4 files changed

+64
-95
lines changed

localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_preproc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ def _deployed_property_value_of(
292292
return property_value
293293
elif resource_type and should_ignore_unsupported_resource_type(
294294
resource_type=resource_type,
295-
change_set_type=getattr(self._change_set, "change_set_type", None),
295+
change_set_type=self._change_set.change_set_type,
296296
):
297297
return MOCKED_REFERENCE
298298

localstack-core/localstack/services/cloudformation/engine/v2/change_set_resource_support_checker.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,12 @@ def _build_resource_failure_message(
8383

8484

8585
class ChangeSetResourceSupportChecker(ChangeSetModelVisitor):
86-
change_set_type: ChangeSetType | str | None
86+
change_set_type: ChangeSetType
8787
catalog: CatalogPlugin
8888

8989
TITLE_MESSAGE = "Unsupported resources detected:"
9090

91-
def __init__(self, change_set_type: ChangeSetType | str | None = None):
91+
def __init__(self, change_set_type: ChangeSetType):
9292
self._resource_failure_messages: dict[str, str] = {}
9393
self.change_set_type = change_set_type
9494
self.catalog = get_aws_catalog()

localstack-core/localstack/services/cloudformation/engine/v2/unsupported_resource.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66

77
def should_ignore_unsupported_resource_type(
8-
resource_type: str, change_set_type: ChangeSetType | str | None
8+
resource_type: str, change_set_type: ChangeSetType
99
) -> bool:
1010
if config.CFN_IGNORE_UNSUPPORTED_RESOURCE_TYPES:
1111
return True

tests/integration/test_catalog.py

Lines changed: 60 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import textwrap
1+
import json
22

33
import pytest
4+
from botocore.exceptions import WaiterError
45

56
from localstack import config
67
from localstack.services.cloudformation.engine.v2 import (
@@ -22,7 +23,6 @@
2223
CloudFormationResourcesSupportInLatest,
2324
)
2425
from localstack.utils.strings import short_uid
25-
from localstack.utils.sync import retry
2626

2727
UNSUPPORTED_RESOURCE_CASES = [
2828
(
@@ -90,74 +90,41 @@ def testing_catalog(monkeypatch):
9090
def test_ignore_unsupported_resources_toggle(testing_catalog, aws_client, monkeypatch, cleanups):
9191
unsupported_resource = "AWS::LatestService::NotSupported"
9292

93-
def _create_change_set(stack_name: str, template_body: str):
94-
change_set_name = f"cs-{short_uid()}"
95-
response = aws_client.cloudformation.create_change_set(
96-
StackName=stack_name,
97-
ChangeSetName=change_set_name,
98-
TemplateBody=template_body,
99-
ChangeSetType="CREATE",
100-
)
101-
return response["Id"], response["StackId"]
102-
103-
def _wait_for_failed_change_set(change_set_id: str):
104-
def _describe():
105-
result = aws_client.cloudformation.describe_change_set(ChangeSetName=change_set_id)
106-
status = result["Status"]
107-
if status == "FAILED":
108-
return result
109-
if status == "CREATE_COMPLETE":
110-
pytest.fail("expected change set creation to fail")
111-
raise Exception("still waiting for change set to fail")
112-
113-
return retry(_describe, retries=15, sleep=2)
114-
115-
def _wait_for_complete_change_set(change_set_id: str):
116-
def _describe():
117-
result = aws_client.cloudformation.describe_change_set(ChangeSetName=change_set_id)
118-
status = result["Status"]
119-
if status == "CREATE_COMPLETE":
120-
return result
121-
if status == "FAILED":
122-
pytest.fail(f"change set unexpectedly failed: {result.get('StatusReason')}")
123-
raise Exception("still waiting for change set")
124-
125-
return retry(_describe, retries=15, sleep=2)
126-
127-
def _wait_for_stack_status(stack_name: str, expected: str):
128-
def _describe():
129-
stack = aws_client.cloudformation.describe_stacks(StackName=stack_name)["Stacks"][0]
130-
status = stack["StackStatus"]
131-
if status == expected:
132-
return stack
133-
if status.endswith("FAILED") or "ROLLBACK" in status:
134-
pytest.fail(f"stack ended in failure: {status} ({stack.get('StackStatusReason')})")
135-
raise Exception("still waiting for stack")
136-
137-
return retry(_describe, retries=30, sleep=2)
138-
13993
# template with one supported and one unsupported resource
14094
bucket_name = f"cfn-toggle-{short_uid()}"
141-
template_body = textwrap.dedent(
142-
f"""
143-
AWSTemplateFormatVersion: '2010-09-09'
144-
Resources:
145-
SupportedBucket:
146-
Type: AWS::S3::Bucket
147-
Properties:
148-
BucketName: {bucket_name}
149-
Unsupported:
150-
Type: {unsupported_resource}
151-
"""
95+
template_body = json.dumps(
96+
{
97+
"Resources": {
98+
"SupportedBucket": {
99+
"Type": "AWS::S3::Bucket",
100+
"Properties": {"BucketName": bucket_name},
101+
},
102+
"Unsupported": {"Type": unsupported_resource},
103+
},
104+
}
152105
)
153106

154107
# 1) ignore lists empty -> change set should fail
155108
monkeypatch.setattr(config, "CFN_IGNORE_UNSUPPORTED_RESOURCE_TYPES", False)
156109
monkeypatch.setattr(config, "CFN_IGNORE_UNSUPPORTED_TYPE_CREATE", [])
157110
stack_name_fail = f"stack-fail-{short_uid()}"
158-
cs_id_fail, stack_id_fail = _create_change_set(stack_name_fail, template_body)
159-
failed_cs = _wait_for_failed_change_set(cs_id_fail)
160-
status_reason = failed_cs.get("StatusReason", "")
111+
change_set_name_fail = f"cs-{short_uid()}"
112+
response = aws_client.cloudformation.create_change_set(
113+
StackName=stack_name_fail,
114+
ChangeSetName=change_set_name_fail,
115+
TemplateBody=template_body,
116+
ChangeSetType="CREATE",
117+
)
118+
cs_id_fail, stack_id_fail = response["Id"], response["StackId"]
119+
120+
waiter = aws_client.cloudformation.get_waiter("change_set_create_complete")
121+
with pytest.raises(WaiterError) as exc_info:
122+
waiter.wait(
123+
ChangeSetName=cs_id_fail,
124+
)
125+
126+
assert exc_info.value.last_response["Status"] == "FAILED"
127+
status_reason = exc_info.value.last_response["StatusReason"]
161128
assert ChangeSetResourceSupportChecker.TITLE_MESSAGE in status_reason
162129
assert unsupported_resource in status_reason
163130
cleanups.append(lambda: aws_client.cloudformation.delete_change_set(ChangeSetName=cs_id_fail))
@@ -166,10 +133,22 @@ def _describe():
166133
# 2) add unsupported resource to create ignore list -> deployment succeeds and bucket is present
167134
monkeypatch.setattr(config, "CFN_IGNORE_UNSUPPORTED_TYPE_CREATE", [unsupported_resource])
168135
stack_name_ok = f"stack-ok-{short_uid()}"
169-
cs_id_ok, stack_id_ok = _create_change_set(stack_name_ok, template_body)
170-
_wait_for_complete_change_set(cs_id_ok)
136+
change_set_name_ok = f"cs-{short_uid()}"
137+
response = aws_client.cloudformation.create_change_set(
138+
StackName=stack_name_ok,
139+
ChangeSetName=change_set_name_ok,
140+
TemplateBody=template_body,
141+
ChangeSetType="CREATE",
142+
)
143+
cs_id_ok, stack_id_ok = response["Id"], response["StackId"]
144+
145+
waiter.wait(
146+
ChangeSetName=cs_id_ok,
147+
)
171148
aws_client.cloudformation.execute_change_set(ChangeSetName=cs_id_ok)
172-
_wait_for_stack_status(stack_name_ok, "CREATE_COMPLETE")
149+
aws_client.cloudformation.get_waiter("stack_create_complete").wait(
150+
StackName=stack_name_ok,
151+
)
173152

174153
buckets = aws_client.s3.list_buckets()["Buckets"]
175154
assert any(b["Name"] == bucket_name for b in buckets)
@@ -186,13 +165,10 @@ def test_catalog_reports_unsupported_resources_in_stack_status(
186165
testing_catalog, aws_client, unsupported_resource, expected_service, monkeypatch, cleanups
187166
):
188167
monkeypatch.setattr(config, "CFN_IGNORE_UNSUPPORTED_RESOURCE_TYPES", False)
189-
template_body = textwrap.dedent(
190-
f"""
191-
AWSTemplateFormatVersion: '2010-09-09'
192-
Resources:
193-
Unsupported:
194-
Type: {unsupported_resource}
195-
"""
168+
template_body = json.dumps(
169+
{
170+
"Resources": {"Unsupported": {"Type": unsupported_resource}},
171+
}
196172
)
197173

198174
stack_name = f"stack-{short_uid()}"
@@ -209,29 +185,22 @@ def test_catalog_reports_unsupported_resources_in_stack_status(
209185
change_set_id = response["Id"]
210186
stack_id = response["StackId"]
211187

212-
def _describe_failed_change_set():
213-
result = aws_client.cloudformation.describe_change_set(ChangeSetName=change_set_id)
214-
status = result["Status"]
215-
if status == "FAILED":
216-
return result
217-
if status == "CREATE_COMPLETE":
218-
pytest.fail("expected change set creation to fail for unsupported resource")
219-
raise Exception("gave up on waiting for change set creation to fail")
220-
221-
change_set = retry(_describe_failed_change_set, retries=20, sleep=2)
222-
223-
status_reason = change_set.get("StatusReason", "")
188+
waiter = aws_client.cloudformation.get_waiter("change_set_create_complete")
189+
with pytest.raises(WaiterError) as exc_info:
190+
waiter.wait(
191+
ChangeSetName=change_set_id,
192+
)
193+
assert exc_info.value.last_response["Status"] == "FAILED"
194+
status_reason = exc_info.value.last_response["StatusReason"]
224195
assert ChangeSetResourceSupportChecker.TITLE_MESSAGE in status_reason
225196
assert unsupported_resource in status_reason
226197

227-
def _describe_failed_stack():
228-
stack = aws_client.cloudformation.describe_stacks(StackName=stack_id)["Stacks"][0]
229-
stack_status = stack["StackStatus"]
230-
if stack_status in {"CREATE_FAILED", "ROLLBACK_COMPLETE"}:
231-
return stack
232-
raise Exception("gave on waiting for stack creation to fail for unsupported resource")
198+
with pytest.raises(WaiterError) as exc_info:
199+
aws_client.cloudformation.get_waiter("stack_create_complete").wait(
200+
StackName=stack_id,
201+
)
233202

234-
stack_description = retry(_describe_failed_stack, retries=30, sleep=2)
203+
stack_description = exc_info.value.last_response["Stacks"][0]
235204
stack_status_reason = stack_description.get("StackStatusReason", "")
236205
assert ChangeSetResourceSupportChecker.TITLE_MESSAGE in stack_status_reason
237206
assert unsupported_resource in stack_status_reason

0 commit comments

Comments
 (0)