diff --git a/IMPLEMENTATION_COVERAGE.md b/IMPLEMENTATION_COVERAGE.md index 76944e3fe..e2a3b7af0 100644 --- a/IMPLEMENTATION_COVERAGE.md +++ b/IMPLEMENTATION_COVERAGE.md @@ -329,7 +329,7 @@ - [ ] update_schema - [ ] update_typed_link_facet -## cloudformation - 20% implemented +## cloudformation - 23% implemented - [ ] cancel_update_stack - [ ] continue_update_rollback - [X] create_change_set @@ -350,7 +350,7 @@ - [ ] describe_stack_set_operation - [X] describe_stacks - [ ] estimate_template_cost -- [ ] execute_change_set +- [X] execute_change_set - [ ] get_stack_policy - [ ] get_template - [ ] get_template_summary diff --git a/moto/cloudformation/models.py b/moto/cloudformation/models.py index 42809608b..70c15d697 100644 --- a/moto/cloudformation/models.py +++ b/moto/cloudformation/models.py @@ -188,6 +188,24 @@ class CloudFormationBackend(BaseBackend): self.change_sets[change_set_id] = stack return change_set_id, stack.stack_id + def execute_change_set(self, change_set_name, stack_name=None): + stack = None + if change_set_name in self.change_sets: + # This means arn was passed in + stack = self.change_sets[change_set_name] + else: + for cs in self.change_sets: + if self.change_sets[cs].name == change_set_name: + stack = self.change_sets[cs] + if stack is None: + raise ValidationError(stack_name) + if stack.events[-1].resource_status == 'REVIEW_IN_PROGRESS': + stack._add_stack_event('CREATE_COMPLETE') + else: + stack._add_stack_event('UPDATE_IN_PROGRESS') + stack._add_stack_event('UPDATE_COMPLETE') + return True + def describe_stacks(self, name_or_stack_id): stacks = self.stacks.values() if name_or_stack_id: diff --git a/moto/cloudformation/responses.py b/moto/cloudformation/responses.py index 93d59f686..07d263652 100644 --- a/moto/cloudformation/responses.py +++ b/moto/cloudformation/responses.py @@ -118,6 +118,24 @@ class CloudFormationResponse(BaseResponse): template = self.response_template(CREATE_CHANGE_SET_RESPONSE_TEMPLATE) return template.render(stack_id=stack_id, change_set_id=change_set_id) + @amzn_request_id + def execute_change_set(self): + stack_name = self._get_param('StackName') + change_set_name = self._get_param('ChangeSetName') + self.cloudformation_backend.execute_change_set( + stack_name=stack_name, + change_set_name=change_set_name, + ) + if self.request_json: + return json.dumps({ + 'ExecuteChangeSetResponse': { + 'ExecuteChangeSetResult': {}, + } + }) + else: + template = self.response_template(EXECUTE_CHANGE_SET_RESPONSE_TEMPLATE) + return template.render() + def describe_stacks(self): stack_name_or_id = None if self._get_param('StackName'): @@ -302,6 +320,16 @@ CREATE_CHANGE_SET_RESPONSE_TEMPLATE = """ """ +EXECUTE_CHANGE_SET_RESPONSE_TEMPLATE = """ + + + + + {{ request_id }} + + +""" + DESCRIBE_STACKS_TEMPLATE = """ diff --git a/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py b/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py index d8b8cf142..1f3bfdec7 100644 --- a/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py +++ b/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py @@ -337,6 +337,30 @@ def test_create_change_set_from_s3_url(): assert 'arn:aws:cloudformation:us-east-1:123456789:stack/NewStack' in response['StackId'] +@mock_cloudformation +def test_execute_change_set_w_arn(): + cf_conn = boto3.client('cloudformation', region_name='us-east-1') + change_set = cf_conn.create_change_set( + StackName='NewStack', + TemplateBody=dummy_template_json, + ChangeSetName='NewChangeSet', + ChangeSetType='CREATE', + ) + cf_conn.execute_change_set(ChangeSetName=change_set['Id']) + + +@mock_cloudformation +def test_execute_change_set_w_name(): + cf_conn = boto3.client('cloudformation', region_name='us-east-1') + change_set = cf_conn.create_change_set( + StackName='NewStack', + TemplateBody=dummy_template_json, + ChangeSetName='NewChangeSet', + ChangeSetType='CREATE', + ) + cf_conn.execute_change_set(ChangeSetName='NewStack', StackName='NewStack') + + @mock_cloudformation def test_describe_stack_pagination(): conn = boto3.client('cloudformation', region_name='us-east-1')