Exemple #1
0
    def test_noninteractive_changeset_update_with_stack_policy(self):
        """Test noninteractive changeset update with stack policy."""
        stack_name = "MockStack"

        self.stubber.add_response("create_change_set", {
            'Id': 'CHANGESETID',
            'StackId': 'STACKID'
        })
        changes = []
        changes.append(generate_change())

        self.stubber.add_response(
            "describe_change_set",
            generate_change_set_response(
                status="CREATE_COMPLETE",
                execution_status="AVAILABLE",
                changes=changes,
            ))

        self.stubber.add_response("set_stack_policy", {})

        self.stubber.add_response("execute_change_set", {})

        with self.stubber:
            self.provider.noninteractive_changeset_update(
                fqn=stack_name,
                template=Template(url="http://fake.template.url.com/"),
                old_parameters=[],
                parameters=[],
                stack_policy=Template(body="{}"),
                tags=[],
            )
Exemple #2
0
    def test_generate_cloudformation_args(self):
        """Test generate cloudformation args."""
        stack_name = "mystack"
        template_url = "http://fake.s3url.com/blah.json"
        template_body = '{"fake_body": "woot"}'
        std_args = {
            "stack_name": stack_name,
            "parameters": [],
            "tags": [],
            "template": Template(url=template_url)
        }
        std_return = {
            "StackName": stack_name,
            "Parameters": [],
            "Tags": [],
            "Capabilities": DEFAULT_CAPABILITIES,
            "TemplateURL": template_url
        }
        result = generate_cloudformation_args(**std_args)
        self.assertEqual(result, std_return)

        result = generate_cloudformation_args(service_role="FakeRole",
                                              **std_args)
        service_role_result = copy.deepcopy(std_return)
        service_role_result["RoleARN"] = "FakeRole"
        self.assertEqual(result, service_role_result)

        result = generate_cloudformation_args(change_set_name="MyChanges",
                                              **std_args)
        change_set_result = copy.deepcopy(std_return)
        change_set_result["ChangeSetName"] = "MyChanges"
        self.assertEqual(result, change_set_result)

        # Check stack policy
        stack_policy = Template(body="{}")
        result = generate_cloudformation_args(stack_policy=stack_policy,
                                              **std_args)
        stack_policy_result = copy.deepcopy(std_return)
        stack_policy_result["StackPolicyBody"] = "{}"
        self.assertEqual(result, stack_policy_result)

        # If not TemplateURL is provided, use TemplateBody
        std_args["template"] = Template(body=template_body)
        template_body_result = copy.deepcopy(std_return)
        del template_body_result["TemplateURL"]
        template_body_result["TemplateBody"] = template_body
        result = generate_cloudformation_args(**std_args)
        self.assertEqual(result, template_body_result)
Exemple #3
0
    def test_create_change_set_stack_did_not_change(self) -> None:
        """Test create change set stack did not change."""
        self.stubber.add_response(
            "create_change_set", {"Id": "CHANGESETID", "StackId": "STACKID"}
        )

        self.stubber.add_response(
            "describe_change_set",
            generate_change_set_response(
                "FAILED", status_reason="Stack didn't contain changes."
            ),
        )

        self.stubber.add_response(
            "delete_change_set", {}, expected_params={"ChangeSetName": "CHANGESETID"}
        )

        with self.stubber:
            with self.assertRaises(exceptions.StackDidNotChange):
                create_change_set(
                    cfn_client=self.cfn,
                    fqn="my-fake-stack",
                    template=Template(url="http://fake.template.url.com/"),
                    parameters=[],
                    tags=[],
                )
Exemple #4
0
    def test_update_stack_execute_success_no_stack_policy(
        self, patched_approval: MagicMock, patched_update_term: MagicMock
    ) -> None:
        """Test update stack execute success no stack policy."""
        stack_name = "my-fake-stack"

        self.stubber.add_response(
            "create_change_set", {"Id": "CHANGESETID", "StackId": "STACKID"}
        )
        changes = [generate_change()]

        self.stubber.add_response(
            "describe_change_set",
            generate_change_set_response(
                status="CREATE_COMPLETE", execution_status="AVAILABLE", changes=changes
            ),
        )

        self.stubber.add_response("execute_change_set", {})

        with self.stubber:
            self.provider.update_stack(
                fqn=stack_name,
                template=Template(url="http://fake.template.url.com/"),
                old_parameters=[],
                parameters=[],
                tags=[],
            )

        patched_approval.assert_called_once_with(
            full_changeset=changes, params_diff=[], include_verbose=True, fqn=stack_name
        )
        patched_update_term.assert_called_once_with(stack_name, False)
Exemple #5
0
    def test_noninteractive_changeset_update_no_stack_policy(self) -> None:
        """Test noninteractive changeset update no stack policy."""
        self.stubber.add_response(
            "create_change_set", {"Id": "CHANGESETID", "StackId": "STACKID"}
        )
        changes = [generate_change()]
        self.stubber.add_response(
            "describe_change_set",
            generate_change_set_response(
                status="CREATE_COMPLETE", execution_status="AVAILABLE", changes=changes
            ),
        )

        self.stubber.add_response("execute_change_set", {})

        with self.stubber:
            stack_name = "MockStack"
            self.provider.noninteractive_changeset_update(
                fqn=stack_name,
                template=Template(url="http://fake.template.url.com/"),
                old_parameters=[],
                parameters=[],
                stack_policy=None,
                tags=[],
            )
Exemple #6
0
    def test_get_stack_changes_create(self, mock_output_full_cs: MagicMock) -> None:
        """Test get stack changes create."""
        stack_name = "MockStack"
        mock_stack = generate_stack_object(stack_name)

        self.stubber.add_response(
            "describe_stacks",
            {
                "Stacks": [
                    generate_describe_stacks_stack(
                        stack_name, stack_status="REVIEW_IN_PROGRESS"
                    )
                ]
            },
        )
        self.stubber.add_response(
            "create_change_set", {"Id": "CHANGESETID", "StackId": stack_name}
        )
        changes = [generate_change()]
        self.stubber.add_response(
            "describe_change_set",
            generate_change_set_response(
                status="CREATE_COMPLETE", execution_status="AVAILABLE", changes=changes
            ),
        )
        self.stubber.add_response("delete_change_set", {})
        self.stubber.add_response(
            "describe_stacks",
            {
                "Stacks": [
                    generate_describe_stacks_stack(
                        stack_name, stack_status="REVIEW_IN_PROGRESS"
                    )
                ]
            },
        )
        self.stubber.add_response(
            "describe_stacks",
            {
                "Stacks": [
                    generate_describe_stacks_stack(
                        stack_name, stack_status="REVIEW_IN_PROGRESS"
                    )
                ]
            },
        )

        self.stubber.add_response("delete_stack", {})

        with self.stubber:
            self.provider.get_stack_changes(
                stack=mock_stack,
                template=Template(url="http://fake.template.url.com/"),
                parameters=[],
                tags=[],
            )

        mock_output_full_cs.assert_called_with(
            full_changeset=changes, params_diff=[], fqn=stack_name, answer="y"
        )
Exemple #7
0
    def test_create_stack_with_changeset(self, patched_create_change_set,
                                         patched_update_term):
        """Test create_stack, force changeset, termination protection."""
        stack_name = 'fake_stack'
        template_path = Path('./tests/cfngin/fixtures/cfn_template.yaml')
        template = Template(body=template_path.read_text())
        parameters = []
        tags = []

        changeset_id = 'CHANGESETID'

        patched_create_change_set.return_value = ([], changeset_id)

        self.stubber.add_response('execute_change_set', {},
                                  {'ChangeSetName': changeset_id})

        with self.stubber:
            self.provider.create_stack(stack_name,
                                       template,
                                       parameters,
                                       tags,
                                       force_change_set=True,
                                       termination_protection=True)
        self.stubber.assert_no_pending_responses()

        patched_create_change_set.assert_called_once_with(
            self.provider.cloudformation,
            stack_name,
            template,
            parameters,
            tags,
            'CREATE',
            service_role=self.provider.service_role)
        patched_update_term.assert_called_once_with(stack_name, True)
Exemple #8
0
    def test_get_stack_changes_create(self, mock_output_full_cs):
        """Test get stack changes create."""
        stack_name = "MockStack"
        mock_stack = generate_stack_object(stack_name)

        self.stubber.add_response(
            'describe_stacks', {
                'Stacks': [
                    generate_describe_stacks_stack(
                        stack_name, stack_status='REVIEW_IN_PROGRESS')
                ]
            })
        self.stubber.add_response("create_change_set", {
            'Id': 'CHANGESETID',
            'StackId': stack_name
        })
        changes = []
        changes.append(generate_change())

        self.stubber.add_response(
            "describe_change_set",
            generate_change_set_response(
                status="CREATE_COMPLETE",
                execution_status="AVAILABLE",
                changes=changes,
            ))
        self.stubber.add_response("delete_change_set", {})
        self.stubber.add_response(
            'describe_stacks', {
                'Stacks': [
                    generate_describe_stacks_stack(
                        stack_name, stack_status='REVIEW_IN_PROGRESS')
                ]
            })
        self.stubber.add_response(
            'describe_stacks', {
                'Stacks': [
                    generate_describe_stacks_stack(
                        stack_name, stack_status='REVIEW_IN_PROGRESS')
                ]
            })

        self.stubber.add_response("delete_stack", {})

        with self.stubber:
            self.provider.get_stack_changes(
                stack=mock_stack,
                template=Template(url="http://fake.template.url.com/"),
                parameters=[],
                tags=[])

        mock_output_full_cs.assert_called_with(full_changeset=changes,
                                               params_diff=[],
                                               fqn=stack_name,
                                               answer='y')
Exemple #9
0
    def test_update_stack_execute_success_with_stack_policy(
            self, patched_approval):
        """Test update stack execute success with stack policy."""
        stack_name = "my-fake-stack"

        self.stubber.add_response("create_change_set", {
            'Id': 'CHANGESETID',
            'StackId': 'STACKID'
        })
        changes = []
        changes.append(generate_change())

        self.stubber.add_response(
            "describe_change_set",
            generate_change_set_response(
                status="CREATE_COMPLETE",
                execution_status="AVAILABLE",
                changes=changes,
            ))

        self.stubber.add_response("set_stack_policy", {})

        self.stubber.add_response("execute_change_set", {})

        with self.stubber:
            self.provider.update_stack(
                fqn=stack_name,
                template=Template(url="http://fake.template.url.com/"),
                old_parameters=[],
                parameters=[],
                tags=[],
                stack_policy=Template(body="{}"),
            )

        patched_approval.assert_called_with(full_changeset=changes,
                                            params_diff=[],
                                            include_verbose=True,
                                            fqn=stack_name)

        self.assertEqual(patched_approval.call_count, 1)
Exemple #10
0
    def test_get_stack_changes_update(self, mock_output_full_cs):
        """Test get stack changes update."""
        stack_name = "MockStack"
        mock_stack = generate_stack_object(stack_name)

        self.stubber.add_response(
            'describe_stacks',
            {'Stacks': [generate_describe_stacks_stack(stack_name)]})
        self.stubber.add_response('get_template',
                                  generate_get_template('cfn_template.yaml'))
        self.stubber.add_response("create_change_set", {
            'Id': 'CHANGESETID',
            'StackId': stack_name
        })
        changes = []
        changes.append(generate_change())

        self.stubber.add_response(
            "describe_change_set",
            generate_change_set_response(
                status="CREATE_COMPLETE",
                execution_status="AVAILABLE",
                changes=changes,
            ))
        self.stubber.add_response("delete_change_set", {})
        self.stubber.add_response(
            'describe_stacks',
            {'Stacks': [generate_describe_stacks_stack(stack_name)]})

        with self.stubber:
            result = self.provider.get_stack_changes(
                stack=mock_stack,
                template=Template(url="http://fake.template.url.com/"),
                parameters=[],
                tags=[])

        mock_output_full_cs.assert_called_with(full_changeset=changes,
                                               params_diff=[],
                                               fqn=stack_name,
                                               answer='y')
        expected_outputs = {
            'FakeOutput':
            '<inferred-change: MockStack.FakeOutput={}>'.format(
                str({"Ref": "FakeResource"}))
        }
        self.assertEqual(self.provider.get_outputs(stack_name),
                         expected_outputs)
        self.assertEqual(result, expected_outputs)
Exemple #11
0
    def test_create_stack_no_changeset(self):
        """Test create_stack, no changeset, template url."""
        stack_name = "fake_stack"
        template = Template(url="http://fake.template.url.com/")
        parameters = []
        tags = []

        expected_args = generate_cloudformation_args(stack_name, parameters,
                                                     tags, template)
        expected_args["EnableTerminationProtection"] = False

        self.stubber.add_response("create_stack", {"StackId": stack_name},
                                  expected_args)

        with self.stubber:
            self.provider.create_stack(stack_name, template, parameters, tags)
        self.stubber.assert_no_pending_responses()
Exemple #12
0
    def test_get_stack_changes_interactive(self, mock_output_summary,
                                           mock_output_full_cs):
        """Test get stack changes interactive."""
        stack_name = "MockStack"
        mock_stack = generate_stack_object(stack_name)

        self.stubber.add_response(
            'describe_stacks',
            {'Stacks': [generate_describe_stacks_stack(stack_name)]})
        self.stubber.add_response('get_template',
                                  generate_get_template('cfn_template.yaml'))
        self.stubber.add_response("create_change_set", {
            'Id': 'CHANGESETID',
            'StackId': stack_name
        })
        changes = []
        changes.append(generate_change())

        self.stubber.add_response(
            "describe_change_set",
            generate_change_set_response(
                status="CREATE_COMPLETE",
                execution_status="AVAILABLE",
                changes=changes,
            ))
        self.stubber.add_response("delete_change_set", {})
        self.stubber.add_response(
            'describe_stacks',
            {'Stacks': [generate_describe_stacks_stack(stack_name)]})

        with self.stubber:
            self.provider.get_stack_changes(
                stack=mock_stack,
                template=Template(url="http://fake.template.url.com/"),
                parameters=[],
                tags=[])

        mock_output_summary.assert_called_with(stack_name,
                                               'changes',
                                               changes, [],
                                               replacements_only=False)
        mock_output_full_cs.assert_called_with(full_changeset=changes,
                                               params_diff=[],
                                               fqn=stack_name)
Exemple #13
0
    def test_get_stack_changes_update(self, mock_output_full_cs: MagicMock) -> None:
        """Test get stack changes update."""
        stack_name = "MockStack"
        mock_stack = generate_stack_object(stack_name)

        self.stubber.add_response(
            "describe_stacks", {"Stacks": [generate_describe_stacks_stack(stack_name)]}
        )
        self.stubber.add_response(
            "get_template", generate_get_template("cfn_template.yaml")
        )
        self.stubber.add_response(
            "create_change_set", {"Id": "CHANGESETID", "StackId": stack_name}
        )
        changes = [generate_change()]
        self.stubber.add_response(
            "describe_change_set",
            generate_change_set_response(
                status="CREATE_COMPLETE", execution_status="AVAILABLE", changes=changes
            ),
        )
        self.stubber.add_response("delete_change_set", {})
        self.stubber.add_response(
            "describe_stacks", {"Stacks": [generate_describe_stacks_stack(stack_name)]}
        )

        with self.stubber:
            result = self.provider.get_stack_changes(
                stack=mock_stack,
                template=Template(url="http://fake.template.url.com/"),
                parameters=[],
                tags=[],
            )

        mock_output_full_cs.assert_called_with(
            full_changeset=changes, params_diff=[], fqn=stack_name, answer="y"
        )
        expected_outputs = {
            "FakeOutput": "<inferred-change: MockStack.FakeOutput={}>".format(
                str({"Ref": "FakeResource"})
            )
        }
        self.assertEqual(self.provider.get_outputs(stack_name), expected_outputs)
        self.assertEqual(result, expected_outputs)
Exemple #14
0
    def test_get_stack_changes_interactive(
        self, mock_output_summary: MagicMock, mock_output_full_cs: MagicMock
    ) -> None:
        """Test get stack changes interactive."""
        stack_name = "MockStack"
        mock_stack = generate_stack_object(stack_name)

        self.stubber.add_response(
            "describe_stacks", {"Stacks": [generate_describe_stacks_stack(stack_name)]}
        )
        self.stubber.add_response(
            "get_template", generate_get_template("cfn_template.yaml")
        )
        self.stubber.add_response(
            "create_change_set", {"Id": "CHANGESETID", "StackId": stack_name}
        )
        changes = [generate_change()]
        self.stubber.add_response(
            "describe_change_set",
            generate_change_set_response(
                status="CREATE_COMPLETE", execution_status="AVAILABLE", changes=changes
            ),
        )
        self.stubber.add_response("delete_change_set", {})
        self.stubber.add_response(
            "describe_stacks", {"Stacks": [generate_describe_stacks_stack(stack_name)]}
        )

        with self.stubber:
            self.provider.get_stack_changes(
                stack=mock_stack,
                template=Template(url="http://fake.template.url.com/"),
                parameters=[],
                tags=[],
            )

        mock_output_summary.assert_called_with(
            stack_name, "changes", changes, [], replacements_only=False
        )
        mock_output_full_cs.assert_called_with(
            full_changeset=changes, params_diff=[], fqn=stack_name
        )
Exemple #15
0
    def test_create_change_set_unhandled_failed_status(self):
        """Test create change set unhandled failed status."""
        self.stubber.add_response("create_change_set", {
            'Id': 'CHANGESETID',
            'StackId': 'STACKID'
        })

        self.stubber.add_response(
            "describe_change_set",
            generate_change_set_response(
                "FAILED", status_reason="Some random bad thing."))

        with self.stubber:
            with self.assertRaises(exceptions.UnhandledChangeSetStatus):
                create_change_set(
                    cfn_client=self.cfn,
                    fqn="my-fake-stack",
                    template=Template(url="http://fake.template.url.com/"),
                    parameters=[],
                    tags=[])
Exemple #16
0
    def test_create_stack_with_changeset(
        self, patched_create_change_set: MagicMock, patched_update_term: MagicMock
    ) -> None:
        """Test create_stack, force changeset, termination protection."""
        stack_name = "fake_stack"
        template_path = Path("./tests/unit/cfngin/fixtures/cfn_template.yaml")
        template = Template(body=template_path.read_text())
        parameters: List[Any] = []
        tags: List[Any] = []

        changeset_id = "CHANGESETID"

        patched_create_change_set.return_value = ([], changeset_id)

        self.stubber.add_response(
            "execute_change_set", {}, {"ChangeSetName": changeset_id}
        )

        with self.stubber:
            self.provider.create_stack(
                stack_name,
                template,
                parameters,
                tags,
                force_change_set=True,
                termination_protection=True,
            )
        self.stubber.assert_no_pending_responses()

        patched_create_change_set.assert_called_once_with(
            self.provider.cloudformation,
            stack_name,
            template,
            parameters,
            tags,
            "CREATE",
            service_role=self.provider.service_role,
        )
        patched_update_term.assert_called_once_with(stack_name, True)
Exemple #17
0
    def test_create_change_set_bad_execution_status(self):
        """Test create change set bad execution status."""
        self.stubber.add_response("create_change_set", {
            'Id': 'CHANGESETID',
            'StackId': 'STACKID'
        })

        self.stubber.add_response(
            "describe_change_set",
            generate_change_set_response(
                status="CREATE_COMPLETE",
                execution_status="UNAVAILABLE",
            ))

        with self.stubber:
            with self.assertRaises(exceptions.UnableToExecuteChangeSet):
                create_change_set(
                    cfn_client=self.cfn,
                    fqn="my-fake-stack",
                    template=Template(url="http://fake.template.url.com/"),
                    parameters=[],
                    tags=[])