diff --git a/moto/cloudformation/models.py b/moto/cloudformation/models.py index 23cdc0925..d3fb2870d 100644 --- a/moto/cloudformation/models.py +++ b/moto/cloudformation/models.py @@ -449,6 +449,16 @@ class FakeEvent(BaseModel): self.event_id = uuid.uuid4() +def filter_stacks(all_stacks, status_filter): + filtered_stacks = [] + if not status_filter: + return all_stacks + for stack in all_stacks: + if stack.status in status_filter: + filtered_stacks.append(stack) + return filtered_stacks + + class CloudFormationBackend(BaseBackend): def __init__(self): self.stacks = OrderedDict() @@ -681,10 +691,11 @@ class CloudFormationBackend(BaseBackend): def list_change_sets(self): return self.change_sets.values() - def list_stacks(self): - return [v for v in self.stacks.values()] + [ + def list_stacks(self, status_filter=None): + total_stacks = [v for v in self.stacks.values()] + [ v for v in self.deleted_stacks.values() ] + return filter_stacks(total_stacks, status_filter) def get_stack(self, name_or_stack_id): all_stacks = dict(self.deleted_stacks, **self.stacks) diff --git a/moto/cloudformation/responses.py b/moto/cloudformation/responses.py index 92a8b1cab..8672c706d 100644 --- a/moto/cloudformation/responses.py +++ b/moto/cloudformation/responses.py @@ -233,7 +233,8 @@ class CloudFormationResponse(BaseResponse): return template.render(change_sets=change_sets) def list_stacks(self): - stacks = self.cloudformation_backend.list_stacks() + status_filter = self._get_multi_param("StackStatusFilter.member") + stacks = self.cloudformation_backend.list_stacks(status_filter) template = self.response_template(LIST_STACKS_RESPONSE) return template.render(stacks=stacks) diff --git a/tests/test_cloudformation/test_cloudformation_stack_crud.py b/tests/test_cloudformation/test_cloudformation_stack_crud.py index 8749d4cfb..29faa11cf 100644 --- a/tests/test_cloudformation/test_cloudformation_stack_crud.py +++ b/tests/test_cloudformation/test_cloudformation_stack_crud.py @@ -233,6 +233,19 @@ def test_list_stacks(): stacks[0].template_description.should.equal("Stack 1") +@mock_cloudformation_deprecated +def test_list_stacks_with_filter(): + conn = boto.connect_cloudformation() + conn.create_stack("test_stack", template_body=dummy_template_json) + conn.create_stack("test_stack2", template_body=dummy_template_json) + conn.update_stack("test_stack", template_body=dummy_template_json2) + stacks = conn.list_stacks("CREATE_COMPLETE") + stacks.should.have.length_of(1) + stacks[0].template_description.should.equal("Stack 1") + stacks = conn.list_stacks("UPDATE_COMPLETE") + stacks.should.have.length_of(1) + + @mock_cloudformation_deprecated def test_delete_stack_by_name(): conn = boto.connect_cloudformation() diff --git a/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py b/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py index 43f63dca2..1ebce46d7 100644 --- a/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py +++ b/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py @@ -14,6 +14,7 @@ from nose.tools import assert_raises from moto import mock_cloudformation, mock_s3, mock_sqs, mock_ec2 from moto.core import ACCOUNT_ID +from .test_cloudformation_stack_crud import dummy_template_json2 dummy_template = { "AWSTemplateFormatVersion": "2010-09-09", @@ -218,6 +219,18 @@ def test_boto3_list_stacksets_length(): stacksets.should.have.length_of(2) +@mock_cloudformation +def test_boto3_filter_stacks(): + conn = boto3.client("cloudformation", region_name="us-east-1") + conn.create_stack(StackName="test_stack", TemplateBody=dummy_template_json) + conn.create_stack(StackName="test_stack2", TemplateBody=dummy_template_json) + conn.update_stack(StackName="test_stack", TemplateBody=dummy_template_json2) + stacks = conn.list_stacks(StackStatusFilter=["CREATE_COMPLETE"]) + stacks.get("StackSummaries").should.have.length_of(1) + stacks = conn.list_stacks(StackStatusFilter=["UPDATE_COMPLETE"]) + stacks.get("StackSummaries").should.have.length_of(1) + + @mock_cloudformation def test_boto3_list_stacksets_contents(): cf_conn = boto3.client("cloudformation", region_name="us-east-1")