예제 #1
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"
        )
예제 #2
0
    def test_create_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.create_stack(stack)

        cloudformation_mock.return_value.create_stack.assert_called_once_with(
            Capabilities=['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM'],
            OnFailure='ROLLBACK',
            Parameters=[('a', 'b')],
            StackName='stack-name',
            Tags=[('any-tag', 'any-tag-value')],
            TemplateBody={'key': 'value'},
            StackPolicyBody='"{foo:baa}"'
        )
예제 #3
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}"'
        )
예제 #4
0
class StackActionHandler(object):
    def __init__(self, config):
        self.logger = get_logger(root=True)
        self.config = config
        self.cfn = CloudFormation(region=self.config.region)
        self.parameter_resolver = ParameterResolver(region=self.config.region)
        self.cli_parameters = config.cli_params

    def create_or_update_stacks(self):
        existing_stacks = self.cfn.get_stack_names()
        desired_stacks = self.config.stacks
        stack_processing_order = DependencyResolver().get_stack_order(desired_stacks)

        if len(stack_processing_order) > 1:
            self.logger.info(
                "Will process stacks in the following order: {0}".format(", ".join(stack_processing_order)))

        for stack_name in stack_processing_order:
            stack_config = self.config.stacks.get(stack_name)

            raw_template = FileLoader.get_file_from_url(stack_config.template_url, stack_config.working_dir)
            template = CloudFormationTemplateTransformer.transform_template(raw_template)

            parameters = self.parameter_resolver.resolve_parameter_values(stack_config.parameters, stack_name)

            merged_parameters = self.parameter_resolver.update_parameters_with_cli_parameters(
                parameters=parameters,
                cli_parameters=self.cli_parameters,
                stack_name=stack_name)

            stack = CloudFormationStack(template=template, parameters=merged_parameters, tags=self.config.tags,
                                        name=stack_name, region=self.config.region, timeout=stack_config.timeout)

            if stack_name in existing_stacks:

                self.cfn.validate_stack_is_ready_for_action(stack)
                self.cfn.update_stack(stack)
            else:
                self.cfn.create_stack(stack)

            CustomResourceHandler.process_post_resources(stack)

    def delete_stacks(self):
        existing_stacks = self.cfn.get_stack_names()
        stacks = self.config.stacks

        stack_processing_order = DependencyResolver().get_stack_order(stacks)
        stack_processing_order.reverse()

        self.logger.info("Will delete stacks in the following order: {0}".format(", ".join(stack_processing_order)))

        for stack_name in stack_processing_order:
            if stack_name in existing_stacks:
                stack = CloudFormationStack(None, None, stack_name, None, None)
                self.cfn.validate_stack_is_ready_for_action(stack)
                self.cfn.delete_stack(stack)
            else:
                self.logger.info("Stack {0} is already deleted".format(stack_name))
예제 #5
0
    def test_create_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.create_stack(stack)

        wait_mock.assert_called_once_with(stack.name, 'create', stack.timeout)
예제 #6
0
    def test_create_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.create_stack(stack)

        cloudformation_mock.return_value.create_stack.assert_called_once_with('stack-name',
                                                                              capabilities=['CAPABILITY_IAM'],
                                                                              parameters=[('a', 'b')],
                                                                              tags=[('any-tag', 'any-tag-value')],
                                                                              template_body={'key': 'value'})
예제 #7
0
    def test_create_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.create_stack(stack)

        cloudformation_mock.return_value.create_stack.assert_called_once_with(
            'stack-name',
            capabilities=['CAPABILITY_IAM'],
            parameters=[('a', 'b')],
            tags=[('any-tag', 'any-tag-value')],
            template_body={'key': 'value'})
예제 #8
0
class StackActionHandler(object):
    def __init__(self, config):
        self.logger = get_logger(root=True)
        self.config = config
        self.cfn = CloudFormation(region=self.config.region)
        self.parameter_resolver = ParameterResolver(region=self.config.region)
        self.cli_parameters = config.cli_params

    def create_or_update_stacks(self):
        existing_stacks = self.cfn.get_stack_names()
        desired_stacks = self.config.stacks
        stack_processing_order = DependencyResolver().get_stack_order(
            desired_stacks)

        if len(stack_processing_order) > 1:
            self.logger.info(
                "Will process stacks in the following order: {0}".format(
                    ", ".join(stack_processing_order)))

        for stack_name in stack_processing_order:
            stack_config = self.config.stacks.get(stack_name)

            if stack_config.stack_policy_url:
                self.logger.info("Using stack policy from {0}".format(
                    stack_config.stack_policy_url))
                stack_policy = FileLoader.get_yaml_or_json_file(
                    stack_config.stack_policy_url, stack_config.working_dir)
            else:
                stack_policy = None

            template = TemplateHandler.get_template(stack_config.template_url,
                                                    stack_config.working_dir)
            parameters = self.parameter_resolver.resolve_parameter_values(
                stack_name, stack_config, self.cli_parameters)

            stack = CloudFormationStack(
                template=template,
                parameters=parameters,
                tags=stack_config.tags,
                name=stack_name,
                region=self.config.region,
                timeout=stack_config.timeout,
                service_role=stack_config.service_role,
                stack_policy=stack_policy,
                failure_action=stack_config.failure_action)

            if stack_name in existing_stacks:

                self.cfn.validate_stack_is_ready_for_action(stack)
                self.cfn.update_stack(stack)
            else:
                self.cfn.create_stack(stack)

    def delete_stacks(self):
        existing_stacks = self.cfn.get_stack_names()
        stacks = self.config.stacks

        stack_processing_order = DependencyResolver().get_stack_order(stacks)
        stack_processing_order.reverse()

        self.logger.info(
            "Will delete stacks in the following order: {0}".format(
                ", ".join(stack_processing_order)))

        for stack_name in stack_processing_order:
            stack_config = self.config.stacks.get(stack_name)

            if stack_name in existing_stacks:
                stack = CloudFormationStack(
                    None,
                    None,
                    stack_name,
                    None,
                    None,
                    service_role=stack_config.service_role)
                self.cfn.validate_stack_is_ready_for_action(stack)
                self.cfn.delete_stack(stack)
            else:
                self.logger.info(
                    "Stack {0} is already deleted".format(stack_name))
예제 #9
0
class StackActionHandler(object):
    def __init__(self, config):
        self.logger = get_logger(root=True)
        self.config = config
        self.cfn = CloudFormation(region=self.config.region)
        self.parameter_resolver = ParameterResolver(region=self.config.region)
        self.cli_parameters = config.cli_params

    def create_or_update_stacks(self):
        existing_stacks = self.cfn.get_stack_names()
        desired_stacks = self.config.stacks
        stack_processing_order = DependencyResolver().get_stack_order(desired_stacks)

        if len(stack_processing_order) > 1:
            self.logger.info(
                "Will process stacks in the following order: {0}".format(", ".join(stack_processing_order))
            )

        for stack_name in stack_processing_order:
            stack_config = self.config.stacks.get(stack_name)

            if stack_config.stack_policy_url:
                self.logger.info("Using stack policy from {0}".format(stack_config.stack_policy_url))
                stack_policy = FileLoader.get_yaml_or_json_file(stack_config.stack_policy_url, stack_config.working_dir)
            else:
                stack_policy = None

            template = TemplateHandler.get_template(stack_config.template_url, stack_config.working_dir)
            parameters = self.parameter_resolver.resolve_parameter_values(stack_name, stack_config, self.cli_parameters)

            stack = CloudFormationStack(
                template=template,
                parameters=parameters,
                tags=stack_config.tags,
                name=stack_name,
                region=self.config.region,
                timeout=stack_config.timeout,
                service_role=stack_config.service_role,
                stack_policy=stack_policy,
                failure_action=stack_config.failure_action,
            )

            if stack_name in existing_stacks:

                self.cfn.validate_stack_is_ready_for_action(stack)
                self.cfn.update_stack(stack)
            else:
                self.cfn.create_stack(stack)

            CustomResourceHandler.process_post_resources(stack)

    def delete_stacks(self):
        existing_stacks = self.cfn.get_stack_names()
        stacks = self.config.stacks

        stack_processing_order = DependencyResolver().get_stack_order(stacks)
        stack_processing_order.reverse()

        self.logger.info("Will delete stacks in the following order: {0}".format(", ".join(stack_processing_order)))

        for stack_name in stack_processing_order:
            stack_config = self.config.stacks.get(stack_name)

            if stack_name in existing_stacks:
                stack = CloudFormationStack(None, None, stack_name, None, None, service_role=stack_config.service_role)
                self.cfn.validate_stack_is_ready_for_action(stack)
                self.cfn.delete_stack(stack)
            else:
                self.logger.info("Stack {0} is already deleted".format(stack_name))
예제 #10
0
class StackActionHandler(object):
    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

    def execute_change_set(self):
        print('executing change set')
        print(self.config.change_set)

        change_set = self.cfn.get_change_set(self.config.change_set)

        if change_set is None:
            raise CfnStackActionFailedException(
                "Could not execute change set {0}: Does not exist or is in an invalid state."
                .format(self.config.change_set))

        stack_name = self.cfn.get_stack_name_by_arn(change_set['StackId'])
        stack = self.cfn.get_stack(stack_name)

        if not self.cfn.change_set_is_executable(change_set):
            raise CfnStackActionFailedException(
                "Could not execute change set {0}: Does not exist or is in an invalid state."
                .format(self.config.change_set))
        else:
            self.cfn.execute_change_set(stack, self.config.change_set)

    def create_change_set(self):
        existing_stacks = self.cfn.get_stack_names()
        desired_stacks = self.config.stacks
        stack_processing_order = DependencyResolver().get_stack_order(
            desired_stacks)

        if len(stack_processing_order) > 1:
            self.logger.info(
                "Will process stacks in the following order: {0}".format(
                    ", ".join(stack_processing_order)))

        for stack_name in stack_processing_order:
            stack_config = self.config.stacks.get(stack_name)

            if stack_config.stack_policy_url:
                self.logger.info("Using stack policy from {0}".format(
                    stack_config.stack_policy_url))
                stack_policy = FileLoader.get_yaml_or_json_file(
                    stack_config.stack_policy_url, stack_config.working_dir)
            else:
                stack_policy = None

            template = TemplateHandler.get_template(
                stack_config.template_url, stack_config.working_dir,
                self.config.region, stack_config.package_bucket)
            parameters = self.parameter_resolver.resolve_parameter_values(
                stack_name, stack_config, self.cli_parameters)

            stack = CloudFormationStack(
                template=template,
                parameters=parameters,
                tags=stack_config.tags,
                name=stack_name,
                region=self.config.region,
                timeout=stack_config.timeout,
                service_role=stack_config.service_role,
                stack_policy=stack_policy,
                failure_action=stack_config.failure_action)

            if stack_name in existing_stacks:
                self.cfn.create_change_set(stack, 'UPDATE')
            else:
                self.cfn.create_change_set(stack, 'CREATE')

    def create_or_update_stacks(self):
        existing_stacks = self.cfn.get_stack_names()
        desired_stacks = self.config.stacks
        stack_processing_order = DependencyResolver().get_stack_order(
            desired_stacks)

        if len(stack_processing_order) > 1:
            self.logger.info(
                "Will process stacks in the following order: {0}".format(
                    ", ".join(stack_processing_order)))

        for stack_name in stack_processing_order:
            stack_config = self.config.stacks.get(stack_name)

            if stack_config.stack_policy_url:
                self.logger.info("Using stack policy from {0}".format(
                    stack_config.stack_policy_url))
                stack_policy = FileLoader.get_yaml_or_json_file(
                    stack_config.stack_policy_url, stack_config.working_dir)
            else:
                stack_policy = None

            template = TemplateHandler.get_template(
                stack_config.template_url, stack_config.working_dir,
                self.config.region, stack_config.package_bucket)
            parameters = self.parameter_resolver.resolve_parameter_values(
                stack_name, stack_config, self.cli_parameters)

            stack = CloudFormationStack(
                template=template,
                parameters=parameters,
                tags=stack_config.tags,
                name=stack_name,
                region=self.config.region,
                timeout=stack_config.timeout,
                service_role=stack_config.service_role,
                stack_policy=stack_policy,
                failure_action=stack_config.failure_action)

            if stack_name in existing_stacks:

                self.cfn.validate_stack_is_ready_for_action(stack)
                self.cfn.update_stack(stack)
            else:
                self.cfn.create_stack(stack)

    def delete_stacks(self):
        existing_stacks = self.cfn.get_stack_names()
        stacks = self.config.stacks

        stack_processing_order = DependencyResolver().get_stack_order(stacks)
        stack_processing_order.reverse()

        self.logger.info(
            "Will delete stacks in the following order: {0}".format(
                ", ".join(stack_processing_order)))

        for stack_name in stack_processing_order:
            stack_config = self.config.stacks.get(stack_name)

            if stack_name in existing_stacks:
                stack = CloudFormationStack(
                    None,
                    None,
                    stack_name,
                    None,
                    None,
                    service_role=stack_config.service_role)
                self.cfn.validate_stack_is_ready_for_action(stack)
                self.cfn.delete_stack(stack)
            else:
                self.logger.info(
                    "Stack {0} is already deleted".format(stack_name))
예제 #11
0
class StackActionHandler(object):
    def __init__(self, config):
        self.logger = get_logger(root=True)
        self.config = config
        self.region = config.region
        self.cfn = CloudFormation(region=self.region)
        self.parameter_resolver = ParameterResolver(region=self.region)

    def create_or_update_stacks(self):
        existing_stacks = self.cfn.get_stack_names()
        desired_stacks = self.config.stacks
        stack_processing_order = DependencyResolver().get_stack_order(
            desired_stacks)

        if len(stack_processing_order) > 1:
            self.logger.info(
                "Will process stacks in the following order: {0}".format(
                    ", ".join(stack_processing_order)))

        for stack_name in stack_processing_order:
            stack_config = self.config.stacks.get(stack_name)

            raw_template = FileLoader.get_file_from_url(
                stack_config.template_url, stack_config.working_dir)
            template = CloudFormationTemplateTransformer.transform_template(
                raw_template)

            parameters = self.parameter_resolver.resolve_parameter_values(
                stack_config.parameters, stack_name)
            stack = CloudFormationStack(template=template,
                                        parameters=parameters,
                                        tags=(stack_config.tags),
                                        name=stack_name,
                                        region=self.region,
                                        timeout=stack_config.timeout)

            if stack_name in existing_stacks:

                self.cfn.validate_stack_is_ready_for_action(stack)
                self.cfn.update_stack(stack)
            else:
                self.cfn.create_stack(stack)

            CustomResourceHandler.process_post_resources(stack)

    def delete_stacks(self):
        existing_stacks = self.cfn.get_stack_names()
        stacks = self.config.stacks

        stack_processing_order = DependencyResolver().get_stack_order(stacks)
        stack_processing_order.reverse()

        self.logger.info(
            "Will delete stacks in the following order: {0}".format(
                ", ".join(stack_processing_order)))

        for stack_name in stack_processing_order:
            if stack_name in existing_stacks:
                stack = CloudFormationStack(None, None, stack_name, None, None)
                self.cfn.validate_stack_is_ready_for_action(stack)
                self.cfn.delete_stack(stack)
            else:
                self.logger.info(
                    "Stack {0} is already deleted".format(stack_name))