Beispiel #1
0
    def test_handle_stack_event_raises_exception_on_rollback_complete(self, _):
        event = {
            'PhysicalResourceId':
            'arn:aws:sns:eu-west-1:1234567890:my-topic',
            'StackName':
            'my-stack',
            'LogicalResourceId':
            'my-stack',
            'StackId':
            'arn:aws:cloudformation:eu-west-1:1234567890:stack/my-stack/my-stack-id',
            'ResourceType':
            'AWS::CloudFormation::Stack',
            'Timestamp':
            datetime.datetime(2016, 4, 1, 8, 3, 27, 548000, tzinfo=tzutc()),
            'EventId':
            'my-event-id',
            'ResourceStatus':
            'ROLLBACK_COMPLETE'
        }
        valid_from_timestamp = datetime.datetime(2016,
                                                 4,
                                                 1,
                                                 8,
                                                 3,
                                                 25,
                                                 548000,
                                                 tzinfo=tzutc())
        cfn = CloudFormation()

        with self.assertRaises(CfnStackActionFailedException):
            cfn.handle_stack_event(event, valid_from_timestamp,
                                   "CREATE_COMPLETE", "my-stack")
Beispiel #2
0
 def __init__(self, config, dry_run=False):
     self.logger = get_logger(root=True)
     self.config = config
     self.cfn = CloudFormation(region=self.config.region, dry_run=dry_run)
     self.parameter_resolver = ParameterResolver(self.cfn,
                                                 region=self.config.region)
     self.cli_parameters = config.cli_params
Beispiel #3
0
    def test_create_stack_calls_cloudformation_api_properly_with_service_role(self, _, cloudformation_mock):
        stack = Mock(spec=CloudFormationStack)
        stack.name = "stack-name"
        stack.get_parameters_list.return_value = [('a', 'b')]
        stack.get_tags_list.return_value = [('any-tag', 'any-tag-value')]
        stack.parameters = {}
        stack.template = Mock(spec=CloudFormationTemplate)
        stack.template.name = "template-name"
        stack.template.get_template_json.return_value = {'key': 'value'}
        stack.service_role = "arn:aws:iam::1234567890:role/my-role"
        stack.stack_policy = None
        stack.failure_action = None
        stack.disable_rollback = False
        stack.timeout = 42

        cfn = CloudFormation()
        cfn.create_stack(stack)

        cloudformation_mock.return_value.create_stack.assert_called_once_with(
            Capabilities=['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM'],
            Parameters=[('a', 'b')],
            StackName='stack-name',
            Tags=[('any-tag', 'any-tag-value')],
            TemplateBody={'key': 'value'},
            RoleARN="arn:aws:iam::1234567890:role/my-role"
        )
Beispiel #4
0
    def test_handle_stack_event_returns_none_on_rollback_in_progress_state(
            self, _):
        event = {
            'PhysicalResourceId':
            'arn:aws:sns:eu-west-1:1234567890:my-topic',
            'StackName':
            'my-stack',
            'LogicalResourceId':
            'my-stack',
            'StackId':
            'arn:aws:cloudformation:eu-west-1:1234567890:stack/my-stack/my-stack-id',
            'ResourceType':
            'AWS::CloudFormation::Stack',
            'Timestamp':
            datetime.datetime(2016, 4, 1, 8, 3, 27, 548000, tzinfo=tzutc()),
            'EventId':
            'my-event-id',
            'ResourceStatus':
            'ROLLBACK_IN_PROGRESS',
            'ResourceStatusReason':
            'Foo'
        }
        valid_from_timestamp = datetime.datetime(2016,
                                                 4,
                                                 1,
                                                 8,
                                                 3,
                                                 25,
                                                 548000,
                                                 tzinfo=tzutc())
        cfn = CloudFormation()

        result = cfn.handle_stack_event(event, valid_from_timestamp,
                                        "CREATE_COMPLETE", "my-stack")
        self.assertIsNone(result)
    def test_wait_for_stack_event_returns_on_start_event_with_valid_timestamp(
            self, cloudformation_mock):
        timestamp = datetime.datetime.utcnow()

        template_mock = Mock(spec=CloudFormationTemplate)
        template_mock.url = "foo.yml"
        template_mock.get_template_body_dict.return_value = {}

        event = StackEvent()
        event.resource_type = "AWS::CloudFormation::Stack"
        event.resource_status = "UPDATE_IN_PROGRESS"
        event.event_id = "123"
        event.timestamp = timestamp

        stack_events_mock = Mock()
        stack_events_mock.describe_stack_events.return_value = [event]

        cloudformation_mock.connect_to_region.return_value = stack_events_mock

        cfn = CloudFormation()
        event = cfn.wait_for_stack_events("foo",
                                          "UPDATE_IN_PROGRESS",
                                          timestamp - timedelta(seconds=10),
                                          timeout=10)

        self.assertEqual(timestamp, event.timestamp)
Beispiel #6
0
    def test_create_stack_calls_cloudformation_api_properly_with_disable_rollback_true(self, _, cloudformation_mock):
        stack = Mock(spec=CloudFormationStack)
        stack.name = "stack-name"
        stack.get_parameters_list.return_value = [('a', 'b')]
        stack.get_tags_list.return_value = [('any-tag', 'any-tag-value')]
        stack.parameters = {}
        stack.template = Mock(spec=CloudFormationTemplate)
        stack.template.name = "template-name"
        stack.template.get_template_json.return_value = {'key': 'value'}
        stack.service_role = None
        stack.stack_policy = "{foo:baa}"
        stack.failure_action = "DO_NOTHING"
        stack.disable_rollback = "True"
        stack.timeout = 42

        cfn = CloudFormation()
        cfn.create_stack(stack)

        cloudformation_mock.return_value.create_stack.assert_called_once_with(
            Capabilities=['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM'],
            OnFailure='DO_NOTHING',
            DisableRollback=True,
            Parameters=[('a', 'b')],
            StackName='stack-name',
            Tags=[('any-tag', 'any-tag-value')],
            TemplateBody={'key': 'value'},
            StackPolicyBody='"{foo:baa}"'
        )
Beispiel #7
0
 def test_stack_exists_returns_false_for_non_existing_stack(
         self, get_stack_mock):
     get_stack_mock.side_effect = ClientError(
         {"Error": {
             "Message": "Stack with id stack3 does not exist"
         }}, "Foo")
     self.assertFalse(CloudFormation().stack_exists("stack3"))
Beispiel #8
0
    def test_update_stack_calls_cloudformation_api_properly_with_stack_policy(
            self, _, cloudformation_mock):
        stack = Mock(spec=CloudFormationStack)
        stack.name = "stack-name"
        stack.get_parameters_list.return_value = [('a', 'b')]
        stack.get_tags_list.return_value = [('any-tag', 'any-tag-value')]
        stack.parameters = {}
        stack.template = Mock(spec=CloudFormationTemplate)
        stack.template.name = "template-name"
        stack.template.get_template_json.return_value = {'key': 'value'}
        stack.service_role = None
        stack.stack_policy = "{foo:baa}"
        stack.timeout = 42

        cfn = CloudFormation()
        cfn.update_stack(stack)

        cloudformation_mock.return_value.set_stack_policy.assert_called_once_with(
            StackName='stack-name', StackPolicyBody='"{foo:baa}"')

        cloudformation_mock.return_value.update_stack.assert_called_once_with(
            Capabilities=['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM'],
            Parameters=[('a', 'b')],
            StackName='stack-name',
            Tags=[('any-tag', 'any-tag-value')],
            TemplateBody={'key': 'value'})
Beispiel #9
0
    def test_handle_stack_event_returns_expected_event(self, _):
        event = {
            'PhysicalResourceId':
            'arn:aws:cloudformation:eu-west-1:1234567890:stack/my-stack/my-stack-id',
            'StackName':
            'my-stack',
            'LogicalResourceId':
            'my-stack',
            'StackId':
            'arn:aws:cloudformation:eu-west-1:1234567890:stack/my-stack/my-stack-id',
            'ResourceType':
            'AWS::CloudFormation::Stack',
            'Timestamp':
            datetime.datetime(2016, 4, 1, 8, 3, 27, 548000, tzinfo=tzutc()),
            'EventId':
            'my-event-id',
            'ResourceStatus':
            'CREATE_COMPLETE'
        }
        valid_from_timestamp = datetime.datetime(2016,
                                                 4,
                                                 1,
                                                 8,
                                                 3,
                                                 25,
                                                 548000,
                                                 tzinfo=tzutc())
        cfn = CloudFormation()

        result = cfn.handle_stack_event(event, valid_from_timestamp,
                                        "CREATE_COMPLETE", "my-stack")
        self.assertDictEqual(event, result)
Beispiel #10
0
 def test_get_stacks_dict_always_returns_empty_list_parameters_and_outputs(
         self, get_stack_descriptions_mock):
     get_stack_descriptions_mock.return_value = [{"StackName": "Foo"}]
     self.assertEqual({'Foo': {
         'outputs': [],
         'parameters': []
     }},
                      CloudFormation().get_stacks_dict())
Beispiel #11
0
    def test_validate_stack_is_ready_for_action_passes_if_stack_is_in_rollback_complete_state(self, get_stack_mock):
        stack_mock = Mock()
        stack_mock.stack_name = "my-stack"
        stack_mock.stack_status = "ROLLBACK_COMPLETE"
        get_stack_mock.return_value = stack_mock

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        cfn.validate_stack_is_ready_for_action(stack)
    def test_get_stacks_correctly_calls_aws_api(self, cloudformation_mock):
        stacks = [Mock(spec=Stack), Mock(spec=Stack)]

        result = ResultSet()
        result.extend(stacks)
        result.next_token = None
        cloudformation_mock.connect_to_region.return_value.describe_stacks.return_value = result

        cfn = CloudFormation()
        self.assertListEqual(stacks, cfn.get_stacks())
Beispiel #13
0
    def test_get_stack_parameters_dict_returns_empty_dict_for_empty_parameters(self, _, get_stack_mock):
        cfn = CloudFormation()

        stack_mock = Mock()
        stack_mock.parameters = []
        get_stack_mock.return_value = stack_mock

        result = cfn.get_stack_parameters_dict('foo')

        self.assertDictEqual({}, result)
Beispiel #14
0
    def test_validate_stack_is_ready_for_action_raises_exception_on_create_in_progress(self, get_stack_mock):
        stack_mock = Mock()
        stack_mock.stack_name = "my-stack"
        stack_mock.stack_status = "CREATE_IN_PROGRESS"
        get_stack_mock.return_value = stack_mock

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        with self.assertRaises(CfnStackActionFailedException):
            cfn.validate_stack_is_ready_for_action(stack)
Beispiel #15
0
    def test_get_stack_parameters_dict_returns_proper_dict(self, _, get_stack_mock):
        cfn = CloudFormation()

        stack_mock = Mock()
        stack_mock.parameters = [{"ParameterKey": "myKey1", "ParameterValue": "myValue1"},
                                 {"ParameterKey": "myKey2", "ParameterValue": "myValue2"}]
        get_stack_mock.return_value = stack_mock

        result = cfn.get_stack_parameters_dict('foo')

        self.assertDictEqual({'myKey1': 'myValue1', 'myKey2': 'myValue2'}, result)
Beispiel #16
0
    def test_validate_stack_is_ready_for_action_raises_exception_on_unknown_stack_state(self, get_stack_mock):
        stack_mock = Mock()
        stack_mock.stack_name = "my-stack"
        stack_mock.stack_status = "FOO"
        get_stack_mock.return_value = stack_mock

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        with self.assertRaises(CfnStackActionFailedException):
            cfn.validate_stack_is_ready_for_action(stack)
Beispiel #17
0
 def test_get_stacks_dict_returns_stack_dict(self,
                                             get_stack_descriptions_mock):
     get_stack_descriptions_mock.return_value = [{
         "StackName": "Foo",
         "Parameters": [],
         "Outputs": []
     }]
     self.assertEqual({'Foo': {
         'outputs': [],
         'parameters': []
     }},
                      CloudFormation().get_stacks_dict())
    def test_validate_stack_is_ready_for_action_raises_proper_exception_on_boto_error(
            self, cloudformation_mock):
        cloudformation_mock.return_value.describe_stacks.side_effect = BotoServerError(
            '400', 'Bad Request')

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        with self.assertRaises(CfnSphereBotoError):
            cfn.validate_stack_is_ready_for_action(stack)

        cloudformation_mock.return_value.describe_stacks.assert_called_once_with(
            'my-stack')
Beispiel #19
0
    def test_validate_stack_is_ready_for_action_raises_proper_exception_on_boto_error(self, get_stack_mock):
        get_stack_mock.side_effect = CfnSphereBotoError(None)

        stack_mock = Mock()
        stack_mock.stack_name = "my-stack"
        stack_mock.stack_status = "UPDATE_COMPLETE"
        get_stack_mock.return_value = stack_mock

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        with self.assertRaises(CfnSphereBotoError):
            cfn.validate_stack_is_ready_for_action(stack)
Beispiel #20
0
    def test_delete_stack_calls_wait_properly(self, wait_mock, _a, _b):
        stack = Mock(spec=CloudFormationStack)
        stack.name = "stack-name"
        stack.get_parameters_list.return_value = []
        stack.parameters = {}
        stack.template = Mock(spec=CloudFormationTemplate)
        stack.template.name = "template-name"

        stack.timeout = 42

        cfn = CloudFormation()
        cfn.delete_stack(stack)

        wait_mock.assert_called_once_with(stack.name, 'delete', stack.timeout)
    def test_validate_stack_is_ready_for_action_passes_if_stack_is_in_good_state(
            self, cloudformation_mock):
        describe_stack_mock = Mock()
        describe_stack_mock.stack_status = "UPDATE_COMPLETE"
        describe_stack_mock.stack_name = "my-stack"

        cloudformation_mock.return_value.describe_stacks.return_value = [
            describe_stack_mock
        ]

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        cfn.validate_stack_is_ready_for_action(stack)

        cloudformation_mock.return_value.describe_stacks.assert_called_once_with(
            'my-stack')
    def test_validate_stack_is_ready_for_action_raises_exception_on_bad_stack_state(
            self, cloudformation_mock):
        describe_stack_mock = Mock()
        describe_stack_mock.stack_status = "UPDATE_IN_PROGRESS"
        describe_stack_mock.stack_name = "my-stack"

        cloudformation_mock.return_value.describe_stacks.return_value = [
            describe_stack_mock
        ]

        stack = CloudFormationStack('', [], 'my-stack', 'my-region')

        cfn = CloudFormation()
        with self.assertRaises(CfnStackActionFailedException):
            cfn.validate_stack_is_ready_for_action(stack)

        cloudformation_mock.return_value.describe_stacks.assert_called_once_with(
            'my-stack')
    def test_get_stacks_correctly_aggregates_paged_results(
            self, cloudformation_mock):
        stacks_1 = [Mock(spec=Stack), Mock(spec=Stack)]
        stacks_2 = [Mock(spec=Stack), Mock(spec=Stack)]

        result_1 = ResultSet()
        result_1.extend(stacks_1)
        result_1.next_token = "my-next-token"

        result_2 = ResultSet()
        result_2.extend(stacks_2)
        result_2.next_token = None

        cloudformation_mock.connect_to_region.return_value.describe_stacks.side_effect = [
            result_1, result_2
        ]

        cfn = CloudFormation()
        self.assertListEqual(stacks_1 + stacks_2, cfn.get_stacks())
Beispiel #24
0
def validate_template(template_file, confirm, yes):
    confirm = confirm or yes
    if not confirm:
        check_update_available()

    try:
        loader = FileLoader()
        template = loader.get_cloudformation_template(template_file, None)
        template = CloudFormationTemplateTransformer.transform_template(template)
        CloudFormation().validate_template(template)
        click.echo("Template is valid")
    except CfnSphereException as e:
        LOGGER.error(e)
        sys.exit(1)
    except Exception as e:
        LOGGER.error("Failed with unexpected error")
        LOGGER.exception(e)
        LOGGER.info("Please report at https://github.com/cfn-sphere/cfn-sphere/issues!")
        sys.exit(1)
Beispiel #25
0
    def test_delete_stack_calls_cloudformation_api_properly(
            self, _, cloudformation_mock):
        stack = Mock(spec=CloudFormationStack)
        stack.name = "stack-name"
        stack.get_parameters_list.return_value = [('a', 'b')]
        stack.get_tags_list.return_value = [('any-tag', 'any-tag-value')]
        stack.parameters = {}
        stack.template = Mock(spec=CloudFormationTemplate)
        stack.template.name = "template-name"
        stack.template.get_template_json.return_value = {'key': 'value'}
        stack.service_role = None
        stack.stack_policy = "{foo:baa}"
        stack.timeout = 42

        cfn = CloudFormation()
        cfn.delete_stack(stack)

        cloudformation_mock.return_value.delete_stack.assert_called_once_with(
            StackName=stack.name)
    def test_update_stack_calls_cloudformation_api_properly(
            self, _, cloudformation_mock):
        stack = Mock(spec=CloudFormationStack)
        stack.name = "stack-name"
        stack.get_parameters_list.return_value = [('a', 'b')]
        stack.tags = [('any-tag', 'any-tag-value')]
        stack.parameters = {}
        stack.template = Mock(spec=CloudFormationTemplate)
        stack.template.name = "template-name"
        stack.template.get_template_json.return_value = {'key': 'value'}
        stack.timeout = 42

        cfn = CloudFormation()
        cfn.update_stack(stack)

        cloudformation_mock.return_value.update_stack.assert_called_once_with(
            'stack-name',
            capabilities=['CAPABILITY_IAM'],
            parameters=[('a', 'b')],
            tags=[('any-tag', 'any-tag-value')],
            template_body={'key': 'value'})
    def test_get_stack_parameters_dict_returns_proper_dict(
            self, _, get_stack_mock):
        cfn = CloudFormation()

        parameter_1 = Mock()
        parameter_1.key = "myKey1"
        parameter_1.value = "myValue1"
        parameter_2 = Mock()
        parameter_2.key = "myKey2"
        parameter_2.value = "myValue2"

        stack_mock = Mock()
        stack_mock.parameters = [parameter_1, parameter_2]
        get_stack_mock.return_value = stack_mock

        result = cfn.get_stack_parameters_dict('foo')

        self.assertDictEqual({
            'myKey1': 'myValue1',
            'myKey2': 'myValue2'
        }, result)
Beispiel #28
0
    def test_set_stack_policy_calls_cloudformation_api_properly(
            self, cloudformation_mock):
        stack = Mock(spec=CloudFormationStack)
        stack.name = "stack-name"
        stack.get_parameters_list.return_value = [('a', 'b')]
        stack.get_tags_list.return_value = [('any-tag', 'any-tag-value')]
        stack.parameters = {}
        stack.template = Mock(spec=CloudFormationTemplate)
        stack.template.name = "template-name"
        stack.template.get_template_json.return_value = {'key': 'value'}
        stack.service_role = None
        stack.stack_policy = """{"Statement":[{"Effect":"Allow"}]}"""
        stack.failure_action = None
        stack.disable_rollback = False
        stack.timeout = 42

        cfn = CloudFormation()
        cfn._set_stack_policy(stack)

        cloudformation_mock.return_value.set_stack_policy.assert_called_once_with(
            StackName='stack-name',
            StackPolicyBody='"{\\"Statement\\":[{\\"Effect\\":\\"Allow\\"}]}"')
    def test_wait_for_stack_event_returns_on_update_complete(
            self, cloudformation_mock):
        timestamp = datetime.datetime.utcnow()

        template_mock = Mock(spec=CloudFormationTemplate)
        template_mock.url = "foo.yml"
        template_mock.get_template_body_dict.return_value = {}

        event = StackEvent()
        event.resource_type = "AWS::CloudFormation::Stack"
        event.resource_status = "UPDATE_COMPLETE"
        event.event_id = "123"
        event.timestamp = timestamp

        stack_events_mock = Mock()
        stack_events_mock.describe_stack_events.return_value = [event]

        cloudformation_mock.connect_to_region.return_value = stack_events_mock

        cfn = CloudFormation()
        cfn.wait_for_stack_events("foo",
                                  "UPDATE_COMPLETE",
                                  timestamp - timedelta(seconds=10),
                                  timeout=10)
    def test_wait_for_stack_event_raises_exception_on_rollback(
            self, cloudformation_mock):
        timestamp = datetime.datetime.utcnow()

        template_mock = Mock(spec=CloudFormationTemplate)
        template_mock.url = "foo.yml"
        template_mock.get_template_body_dict.return_value = {}

        event = StackEvent()
        event.resource_type = "AWS::CloudFormation::Stack"
        event.resource_status = "ROLLBACK_COMPLETE"
        event.event_id = "123"
        event.timestamp = timestamp

        stack_events_mock = Mock()
        stack_events_mock.describe_stack_events.return_value = [event]

        cloudformation_mock.connect_to_region.return_value = stack_events_mock

        cfn = CloudFormation()
        with self.assertRaises(Exception):
            cfn.wait_for_stack_events("foo", ["UPDATE_COMPLETE"],
                                      timestamp - timedelta(seconds=10),
                                      timeout=10)