Skip to content

Commit 9f9a1fa

Browse files
committed
WIP
1 parent e800dce commit 9f9a1fa

File tree

7 files changed

+112
-44
lines changed

7 files changed

+112
-44
lines changed

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

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,18 @@
44
import enum
55
from collections.abc import Generator
66
from itertools import zip_longest
7-
from typing import TYPE_CHECKING, Any, Final, TypedDict, cast
7+
from typing import Any, Final, TypedDict, cast
88

99
from typing_extensions import TypeVar
1010

1111
from localstack.aws.api.cloudformation import ChangeAction
1212
from localstack.services.cloudformation.resource_provider import ResourceProviderExecutor
13+
from localstack.services.cloudformation.v2.types import (
14+
EngineParameter,
15+
engine_parameter_value,
16+
)
1317
from localstack.utils.strings import camel_to_snake_case
1418

15-
if TYPE_CHECKING:
16-
from localstack.services.cloudformation.v2.entities import (
17-
EngineParameter,
18-
engine_parameter_value,
19-
)
20-
2119
T = TypeVar("T")
2220

2321

localstack-core/localstack/services/cloudformation/v2/entities.py

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -29,39 +29,11 @@
2929
ChangeType,
3030
UpdateModel,
3131
)
32+
from localstack.services.cloudformation.v2.types import ResolvedResource
3233
from localstack.utils.aws import arns
3334
from localstack.utils.strings import long_uid, short_uid
3435

3536

36-
# TODO: turn into class/dataclass
37-
class EngineParameter(TypedDict):
38-
"""
39-
Parameters supplied by the user. The resolved value field is populated by the engine
40-
"""
41-
42-
type_: str
43-
given_value: NotRequired[str | None]
44-
resolved_value: NotRequired[str | None]
45-
default_value: NotRequired[str | None]
46-
47-
48-
def engine_parameter_value(parameter: EngineParameter) -> str:
49-
value = parameter.get("given_value") or parameter.get("default_value")
50-
if value is None:
51-
raise RuntimeError("Parameter value is None")
52-
53-
return value
54-
55-
56-
class ResolvedResource(TypedDict):
57-
LogicalResourceId: str
58-
Type: str
59-
Properties: dict
60-
ResourceStatus: ResourceStatus
61-
PhysicalResourceId: str | None
62-
LastUpdatedTimestamp: datetime | None
63-
64-
6537
class Stack:
6638
stack_name: str
6739
description: str | None

localstack-core/localstack/services/cloudformation/v2/provider.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,11 @@
110110
)
111111
from localstack.services.cloudformation.v2.entities import (
112112
ChangeSet,
113-
EngineParameter,
114113
Stack,
115114
StackInstance,
116115
StackSet,
117116
)
117+
from localstack.services.cloudformation.v2.types import EngineParameter
118118
from localstack.utils.collections import select_attributes
119119
from localstack.utils.strings import short_uid
120120
from localstack.utils.threads import start_worker_thread
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from datetime import datetime
2+
from typing import NotRequired, TypedDict
3+
4+
from localstack.aws.api.cloudformation import ResourceStatus
5+
6+
7+
class EngineParameter(TypedDict):
8+
"""
9+
Parameters supplied by the user. The resolved value field is populated by the engine
10+
"""
11+
12+
type_: str
13+
given_value: NotRequired[str | None]
14+
resolved_value: NotRequired[str | None]
15+
default_value: NotRequired[str | None]
16+
17+
18+
def engine_parameter_value(parameter: EngineParameter) -> str:
19+
value = parameter.get("given_value") or parameter.get("default_value")
20+
if value is None:
21+
raise RuntimeError("Parameter value is None")
22+
23+
return value
24+
25+
26+
class ResolvedResource(TypedDict):
27+
LogicalResourceId: str
28+
Type: str
29+
Properties: dict
30+
ResourceStatus: ResourceStatus
31+
PhysicalResourceId: str | None
32+
LastUpdatedTimestamp: datetime | None

tests/aws/services/cloudformation/api/test_update_stack.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import botocore.errorfactory
66
import botocore.exceptions
77
import pytest
8-
from tests.aws.services.cloudformation.conftest import skip_if_v2_provider
98

109
from localstack.testing.pytest import markers
1110
from localstack.utils.files import load_file
@@ -255,16 +254,19 @@ def test_no_parameters_update(deploy_cfn_template, aws_client):
255254
aws_client.cloudformation.get_waiter("stack_update_complete").wait(StackName=stack.stack_name)
256255

257256

258-
@skip_if_v2_provider(reason="CFNV2:UpdateStack")
259257
@markers.aws.validated
260-
def test_update_with_previous_parameter_value(deploy_cfn_template, snapshot, aws_client):
258+
def test_update_with_previous_parameter_value(deploy_cfn_template, aws_client):
259+
topic_name = f"topic-{short_uid()}"
261260
stack = deploy_cfn_template(
262261
template_path=os.path.join(
263262
os.path.dirname(__file__), "../../../templates/sns_topic_parameter.yml"
264263
),
265-
parameters={"TopicName": f"topic-{short_uid()}"},
264+
parameters={"TopicName": topic_name},
266265
)
267266

267+
topic_arn = stack.outputs["TopicArn"]
268+
assert topic_name in topic_arn
269+
268270
aws_client.cloudformation.update_stack(
269271
StackName=stack.stack_name,
270272
TemplateBody=load_file(
@@ -277,6 +279,9 @@ def test_update_with_previous_parameter_value(deploy_cfn_template, snapshot, aws
277279

278280
aws_client.cloudformation.get_waiter("stack_update_complete").wait(StackName=stack.stack_name)
279281

282+
# this call makes sure the topic name has not changed
283+
aws_client.sns.get_topic_attributes(TopicArn=topic_arn)
284+
280285

281286
@markers.aws.validated
282287
@pytest.mark.skip(reason="The correct error is not being raised")

tests/aws/services/cloudformation/api/test_update_stack.snapshot.json

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,63 @@
5959
"recorded-content": {}
6060
},
6161
"tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_previous_parameter_value": {
62-
"recorded-date": "21-11-2022, 10:38:33",
63-
"recorded-content": {}
62+
"recorded-date": "08-08-2025, 21:51:58",
63+
"recorded-content": {
64+
"topic-attributes": {
65+
"DisplayName": "",
66+
"EffectiveDeliveryPolicy": {
67+
"http": {
68+
"defaultHealthyRetryPolicy": {
69+
"minDelayTarget": 20,
70+
"maxDelayTarget": 20,
71+
"numRetries": 3,
72+
"numMaxDelayRetries": 0,
73+
"numNoDelayRetries": 0,
74+
"numMinDelayRetries": 0,
75+
"backoffFunction": "linear"
76+
},
77+
"disableSubscriptionOverrides": false,
78+
"defaultRequestPolicy": {
79+
"headerContentType": "text/plain; charset=UTF-8"
80+
}
81+
}
82+
},
83+
"Owner": "111111111111",
84+
"Policy": {
85+
"Version": "2008-10-17",
86+
"Id": "__default_policy_ID",
87+
"Statement": [
88+
{
89+
"Sid": "__default_statement_ID",
90+
"Effect": "Allow",
91+
"Principal": {
92+
"AWS": "*"
93+
},
94+
"Action": [
95+
"SNS:GetTopicAttributes",
96+
"SNS:SetTopicAttributes",
97+
"SNS:AddPermission",
98+
"SNS:RemovePermission",
99+
"SNS:DeleteTopic",
100+
"SNS:Subscribe",
101+
"SNS:ListSubscriptionsByTopic",
102+
"SNS:Publish"
103+
],
104+
"Resource": "arn:<partition>:sns:<region>:111111111111:topic-e848c848",
105+
"Condition": {
106+
"StringEquals": {
107+
"AWS:SourceOwner": "111111111111"
108+
}
109+
}
110+
}
111+
]
112+
},
113+
"SubscriptionsConfirmed": "0",
114+
"SubscriptionsDeleted": "0",
115+
"SubscriptionsPending": "0",
116+
"TopicArn": "arn:<partition>:sns:<region>:111111111111:topic-e848c848"
117+
}
118+
}
64119
},
65120
"tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_role_without_permissions": {
66121
"recorded-date": "21-11-2022, 14:14:52",

tests/aws/services/cloudformation/api/test_update_stack.validation.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,13 @@
1212
"last_validated_date": "2022-11-21T14:36:32+00:00"
1313
},
1414
"tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_previous_parameter_value": {
15-
"last_validated_date": "2022-11-21T09:38:33+00:00"
15+
"last_validated_date": "2025-08-08T21:55:03+00:00",
16+
"durations_in_seconds": {
17+
"setup": 0.0,
18+
"call": 16.77,
19+
"teardown": 49.74,
20+
"total": 66.51
21+
}
1622
},
1723
"tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_resource_types": {
1824
"last_validated_date": "2022-11-19T13:34:18+00:00"

0 commit comments

Comments
 (0)