Skip to content

Commit c7d27b1

Browse files
committed
same validation for stack update
1 parent 1324520 commit c7d27b1

File tree

4 files changed

+63
-0
lines changed

4 files changed

+63
-0
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,6 +1542,14 @@ def update_stack(
15421542
raise RuntimeError("Multiple stacks matched, update matching logic")
15431543
stack = active_stack_candidates[0]
15441544

1545+
if (
1546+
stack.status == StackStatus.DELETE_COMPLETE
1547+
or stack.status == StackStatus.DELETE_IN_PROGRESS
1548+
):
1549+
raise ValidationError(
1550+
f"Stack:{stack.stack_id} is in {stack.status} state and can not be updated."
1551+
)
1552+
15451553
# TODO: proper status modeling
15461554
before_parameters = stack.resolved_parameters
15471555
# TODO: reconsider the way parameters are modelled in the update graph process.

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

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

910
from localstack.testing.pytest import markers
1011
from localstack.utils.files import load_file
@@ -459,3 +460,32 @@ def test_diff_after_update(deploy_cfn_template, aws_client, snapshot):
459460

460461
describe_stack_response = aws_client.cloudformation.describe_stacks(StackName=stack.stack_name)
461462
assert describe_stack_response["Stacks"][0]["StackStatus"] == "UPDATE_COMPLETE"
463+
464+
465+
@markers.aws.validated
466+
@skip_if_legacy_engine
467+
def test_update_deleted_stack(aws_client, deploy_cfn_template, snapshot):
468+
template = json.dumps(
469+
{
470+
"Resources": {
471+
"Parameter": {
472+
"Type": "AWS::SSM::Parameter",
473+
"Properties": {"Type": "String", "Value": "Test"},
474+
}
475+
}
476+
}
477+
)
478+
479+
stack = deploy_cfn_template(template=template)
480+
stack.destroy()
481+
482+
with pytest.raises(botocore.exceptions.ClientError) as ex:
483+
aws_client.cloudformation.create_change_set(
484+
StackName=stack.stack_id,
485+
ChangeSetName="test",
486+
TemplateBody=template,
487+
ChangeSetType="UPDATE",
488+
)
489+
490+
snapshot.add_transformer(snapshot.transform.regex(stack.stack_id, "<stack-id>"))
491+
snapshot.match("Error", ex.value.response)

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,5 +186,21 @@
186186
}
187187
}
188188
}
189+
},
190+
"tests/aws/services/cloudformation/api/test_update_stack.py::test_update_deleted_stack": {
191+
"recorded-date": "10-10-2025, 21:42:05",
192+
"recorded-content": {
193+
"Error": {
194+
"Error": {
195+
"Code": "ValidationError",
196+
"Message": "Stack:<stack-id> is in DELETE_COMPLETE state and can not be updated.",
197+
"Type": "Sender"
198+
},
199+
"ResponseMetadata": {
200+
"HTTPHeaders": {},
201+
"HTTPStatusCode": 400
202+
}
203+
}
204+
}
189205
}
190206
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@
88
"tests/aws/services/cloudformation/api/test_update_stack.py::test_no_template_error": {
99
"last_validated_date": "2022-11-21T07:57:45+00:00"
1010
},
11+
"tests/aws/services/cloudformation/api/test_update_stack.py::test_update_deleted_stack": {
12+
"last_validated_date": "2025-10-10T21:42:05+00:00",
13+
"durations_in_seconds": {
14+
"setup": 0.25,
15+
"call": 18.99,
16+
"teardown": 0.12,
17+
"total": 19.36
18+
}
19+
},
1120
"tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_invalid_rollback_configuration_errors": {
1221
"last_validated_date": "2022-11-21T14:36:32+00:00"
1322
},

0 commit comments

Comments
 (0)